@avleon/core 0.0.45 → 0.0.46
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/License +21 -21
- package/README.md +667 -681
- package/dist/application.test.js +15 -0
- package/dist/controller.test.js +0 -14
- package/dist/core/application.d.ts +74 -0
- package/dist/core/application.js +424 -0
- package/dist/core/router.d.ts +44 -0
- package/dist/core/router.js +520 -0
- package/dist/core/testing.d.ts +21 -0
- package/dist/core/testing.js +104 -0
- package/dist/core/types.d.ts +67 -0
- package/dist/core/types.js +2 -0
- package/dist/event-dispatcher.d.ts +0 -1
- package/dist/event-dispatcher.js +4 -7
- package/dist/file-storage.test.js +15 -2
- package/dist/helpers.d.ts +9 -42
- package/dist/helpers.js +19 -411
- package/dist/index.d.ts +17 -15
- package/dist/index.js +18 -22
- package/dist/interfaces/avleon-application.d.ts +74 -26
- package/dist/interfaces/avleon-application.js +1 -0
- package/dist/middleware.d.ts +11 -4
- package/dist/middleware.js +9 -0
- package/dist/multipart.d.ts +2 -2
- package/dist/openapi.d.ts +70 -3
- package/dist/openapi.js +32 -0
- package/dist/params.js +1 -1
- package/dist/params.test.js +8 -8
- package/dist/route-methods.js +16 -5
- package/dist/swagger-schema.d.ts +11 -17
- package/dist/swagger-schema.js +84 -82
- package/dist/swagger-schema.test.js +32 -12
- package/dist/utils/common-utils.d.ts +17 -0
- package/dist/utils/common-utils.js +108 -0
- package/dist/utils/di-utils.d.ts +1 -0
- package/dist/utils/di-utils.js +22 -0
- package/dist/utils/hash.d.ts +0 -2
- package/dist/utils/hash.js +1 -5
- package/dist/utils/object-utils.d.ts +11 -0
- package/dist/utils/object-utils.js +198 -0
- package/dist/utils/validation-utils.d.ts +13 -0
- package/dist/utils/validation-utils.js +119 -0
- package/dist/validation.js +1 -4
- package/dist/websocket.d.ts +3 -0
- package/dist/websocket.js +2 -1
- package/package.json +53 -40
- package/dist/application.d.ts +0 -47
- package/dist/application.js +0 -50
- package/dist/icore.d.ts +0 -226
- package/dist/icore.js +0 -968
- package/dist/icore.test.js +0 -14
- package/dist/testing.d.ts +0 -55
- package/dist/testing.js +0 -196
- /package/dist/{icore.test.d.ts → application.test.d.ts} +0 -0
package/dist/swagger-schema.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpenApiProperty = OpenApiProperty;
|
|
4
4
|
exports.CreateSwaggerObjectSchema = CreateSwaggerObjectSchema;
|
|
5
|
+
exports.generateClassSchema = generateClassSchema;
|
|
5
6
|
exports.generateSwaggerSchema = generateSwaggerSchema;
|
|
6
7
|
exports.OpenApiResponse = OpenApiResponse;
|
|
7
8
|
/**
|
|
@@ -11,6 +12,7 @@ exports.OpenApiResponse = OpenApiResponse;
|
|
|
11
12
|
* @url https://github.com/xtareq
|
|
12
13
|
*/
|
|
13
14
|
const class_validator_1 = require("class-validator");
|
|
15
|
+
const container_1 = require("./container");
|
|
14
16
|
// Decorator to add OpenAPI metadata to properties
|
|
15
17
|
function OpenApiProperty(options) {
|
|
16
18
|
return function (target, propertyKey) {
|
|
@@ -39,6 +41,7 @@ function OpenApiProperty(options) {
|
|
|
39
41
|
}
|
|
40
42
|
function extractOpenApiFields(meta) {
|
|
41
43
|
const result = {};
|
|
44
|
+
// ✅ Complete list — was missing required, title, readOnly, writeOnly, nullable
|
|
42
45
|
const jsonSchemaFields = [
|
|
43
46
|
"description",
|
|
44
47
|
"deprecated",
|
|
@@ -54,46 +57,28 @@ function extractOpenApiFields(meta) {
|
|
|
54
57
|
"oneOf",
|
|
55
58
|
"allOf",
|
|
56
59
|
"anyOf",
|
|
60
|
+
"title",
|
|
61
|
+
"readOnly",
|
|
62
|
+
"writeOnly",
|
|
63
|
+
"nullable"
|
|
57
64
|
];
|
|
58
65
|
// Valid JSON Schema formats
|
|
59
66
|
const validFormats = [
|
|
60
|
-
"date-time",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"idn-hostname",
|
|
68
|
-
"ipv4",
|
|
69
|
-
"ipv6",
|
|
70
|
-
"uri",
|
|
71
|
-
"uri-reference",
|
|
72
|
-
"iri",
|
|
73
|
-
"iri-reference",
|
|
74
|
-
"uuid",
|
|
75
|
-
"uri-template",
|
|
76
|
-
"json-pointer",
|
|
77
|
-
"relative-json-pointer",
|
|
78
|
-
"regex",
|
|
79
|
-
"int32",
|
|
80
|
-
"int64",
|
|
81
|
-
"float",
|
|
82
|
-
"double",
|
|
83
|
-
"byte",
|
|
84
|
-
"binary",
|
|
85
|
-
"password",
|
|
67
|
+
"date-time", "date", "time", "duration",
|
|
68
|
+
"email", "idn-email", "hostname", "idn-hostname",
|
|
69
|
+
"ipv4", "ipv6", "uri", "uri-reference",
|
|
70
|
+
"iri", "iri-reference", "uuid", "uri-template",
|
|
71
|
+
"json-pointer", "relative-json-pointer", "regex",
|
|
72
|
+
"int32", "int64", "float", "double",
|
|
73
|
+
"byte", "binary", "password",
|
|
86
74
|
];
|
|
87
75
|
jsonSchemaFields.forEach((field) => {
|
|
88
76
|
if (meta[field] !== undefined) {
|
|
89
|
-
// Validate format field
|
|
90
77
|
if (field === "format") {
|
|
91
78
|
const formatValue = meta[field];
|
|
92
|
-
// Only add format if it's a valid format string
|
|
93
79
|
if (validFormats.includes(formatValue)) {
|
|
94
80
|
result[field] = formatValue;
|
|
95
81
|
}
|
|
96
|
-
// Skip invalid formats
|
|
97
82
|
}
|
|
98
83
|
else {
|
|
99
84
|
result[field] = meta[field];
|
|
@@ -105,17 +90,13 @@ function extractOpenApiFields(meta) {
|
|
|
105
90
|
function CreateSwaggerObjectSchema(classType) {
|
|
106
91
|
const metadataStorage = (0, class_validator_1.getMetadataStorage)();
|
|
107
92
|
const validationMetadata = metadataStorage.getTargetValidationMetadatas(classType, "", true, false);
|
|
108
|
-
const schema = {
|
|
109
|
-
type: "object",
|
|
110
|
-
properties: {},
|
|
111
|
-
required: [],
|
|
112
|
-
};
|
|
93
|
+
const schema = { type: "object", properties: {}, required: [] };
|
|
113
94
|
const prototype = classType.prototype;
|
|
114
95
|
const propertyKeys = new Set();
|
|
115
|
-
// Collect property names
|
|
116
96
|
Object.getOwnPropertyNames(prototype).forEach((k) => propertyKeys.add(k));
|
|
117
97
|
Object.keys(prototype).forEach((k) => propertyKeys.add(k));
|
|
118
98
|
validationMetadata.forEach((m) => propertyKeys.add(m.propertyName));
|
|
99
|
+
// ✅ Discover instance-level properties (class fields with !)
|
|
119
100
|
try {
|
|
120
101
|
const instance = new classType();
|
|
121
102
|
Reflect.ownKeys(instance).forEach((k) => {
|
|
@@ -128,11 +109,9 @@ function CreateSwaggerObjectSchema(classType) {
|
|
|
128
109
|
var _a;
|
|
129
110
|
if (!propertyName || propertyName === "constructor")
|
|
130
111
|
return;
|
|
131
|
-
// Get decorator metadata
|
|
132
112
|
const openApiMeta = Reflect.getMetadata("property:openapi", prototype, propertyName);
|
|
133
113
|
if (openApiMeta === null || openApiMeta === void 0 ? void 0 : openApiMeta.exclude)
|
|
134
114
|
return;
|
|
135
|
-
// Get TypeScript type
|
|
136
115
|
const propertyType = Reflect.getMetadata("design:type", prototype, propertyName);
|
|
137
116
|
let swaggerProperty = {};
|
|
138
117
|
switch (propertyType) {
|
|
@@ -151,7 +130,7 @@ function CreateSwaggerObjectSchema(classType) {
|
|
|
151
130
|
break;
|
|
152
131
|
case Array:
|
|
153
132
|
swaggerProperty.type = "array";
|
|
154
|
-
swaggerProperty.items = { type: "string" };
|
|
133
|
+
swaggerProperty.items = { type: "string" };
|
|
155
134
|
break;
|
|
156
135
|
case Object:
|
|
157
136
|
swaggerProperty = CreateSwaggerObjectSchema(propertyType);
|
|
@@ -170,7 +149,6 @@ function CreateSwaggerObjectSchema(classType) {
|
|
|
170
149
|
...openApiMeta,
|
|
171
150
|
...extractOpenApiFields(openApiMeta),
|
|
172
151
|
};
|
|
173
|
-
// 🪄 Auto-handle file uploads
|
|
174
152
|
if (openApiMeta.format === "binary") {
|
|
175
153
|
if (openApiMeta.isArray || propertyType === Array) {
|
|
176
154
|
swaggerProperty = {
|
|
@@ -190,7 +168,6 @@ function CreateSwaggerObjectSchema(classType) {
|
|
|
190
168
|
}
|
|
191
169
|
schema.properties[propertyName] = swaggerProperty;
|
|
192
170
|
});
|
|
193
|
-
// Handle validation decorators
|
|
194
171
|
validationMetadata.forEach((meta) => {
|
|
195
172
|
const propertyName = meta.propertyName;
|
|
196
173
|
const property = schema.properties[propertyName];
|
|
@@ -199,9 +176,8 @@ function CreateSwaggerObjectSchema(classType) {
|
|
|
199
176
|
switch (meta.name) {
|
|
200
177
|
case "isNotEmpty":
|
|
201
178
|
case "isDefined":
|
|
202
|
-
if (!schema.required.includes(propertyName))
|
|
179
|
+
if (!schema.required.includes(propertyName))
|
|
203
180
|
schema.required.push(propertyName);
|
|
204
|
-
}
|
|
205
181
|
break;
|
|
206
182
|
case "isOptional":
|
|
207
183
|
schema.required = schema.required.filter((item) => item !== propertyName);
|
|
@@ -241,24 +217,32 @@ function CreateSwaggerObjectSchema(classType) {
|
|
|
241
217
|
break;
|
|
242
218
|
}
|
|
243
219
|
});
|
|
244
|
-
if (schema.required.length === 0)
|
|
220
|
+
if (schema.required.length === 0)
|
|
245
221
|
delete schema.required;
|
|
246
|
-
}
|
|
247
222
|
return schema;
|
|
248
223
|
}
|
|
249
|
-
function
|
|
224
|
+
function generateClassSchema(classType) {
|
|
225
|
+
const schema = { type: "object", properties: {}, required: [] };
|
|
226
|
+
// ✅ Guard against null/undefined
|
|
227
|
+
if (!classType || !classType.prototype)
|
|
228
|
+
return schema;
|
|
250
229
|
const metadataStorage = (0, class_validator_1.getMetadataStorage)();
|
|
251
230
|
const validationMetadata = metadataStorage.getTargetValidationMetadatas(classType, "", true, false);
|
|
252
|
-
const schema = {
|
|
253
|
-
type: "object",
|
|
254
|
-
properties: {},
|
|
255
|
-
required: [],
|
|
256
|
-
};
|
|
257
231
|
const prototype = classType.prototype;
|
|
258
232
|
const propertyKeys = new Set([
|
|
259
233
|
...Object.getOwnPropertyNames(prototype),
|
|
260
234
|
...validationMetadata.map((m) => m.propertyName),
|
|
261
235
|
]);
|
|
236
|
+
// ✅ Discover instance-level class fields (e.g. `search!: string`)
|
|
237
|
+
// These don't appear on prototype — only on instantiated objects
|
|
238
|
+
try {
|
|
239
|
+
const instance = new classType();
|
|
240
|
+
Reflect.ownKeys(instance).forEach((k) => {
|
|
241
|
+
if (typeof k === "string")
|
|
242
|
+
propertyKeys.add(k);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
catch (_) { }
|
|
262
246
|
propertyKeys.forEach((propertyName) => {
|
|
263
247
|
var _a;
|
|
264
248
|
if (!propertyName || propertyName === "constructor")
|
|
@@ -284,36 +268,40 @@ function generateSwaggerSchema(classType) {
|
|
|
284
268
|
break;
|
|
285
269
|
case Array:
|
|
286
270
|
swaggerProperty.type = "array";
|
|
287
|
-
swaggerProperty.items = { type: "string" };
|
|
271
|
+
swaggerProperty.items = { type: "string" };
|
|
288
272
|
break;
|
|
289
273
|
case Object:
|
|
290
|
-
swaggerProperty =
|
|
274
|
+
swaggerProperty = generateClassSchema(propertyType);
|
|
291
275
|
break;
|
|
292
276
|
default:
|
|
293
|
-
|
|
277
|
+
if (propertyType && typeof propertyType === "function") {
|
|
278
|
+
swaggerProperty.$ref = `#/components/schemas/${propertyType.name}`;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
swaggerProperty.type = ((_a = propertyType === null || propertyType === void 0 ? void 0 : propertyType.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "string";
|
|
282
|
+
}
|
|
294
283
|
}
|
|
295
|
-
// Apply OpenApi metadata
|
|
284
|
+
// ✅ Apply OpenApi metadata — extractOpenApiFields now includes all fields
|
|
296
285
|
if (openApiMeta) {
|
|
286
|
+
const { required: _required, exclude: _exclude, isArray: _isArray, ...safeOpenApiMeta } = openApiMeta;
|
|
297
287
|
swaggerProperty = {
|
|
298
288
|
...swaggerProperty,
|
|
299
|
-
...extractOpenApiFields(
|
|
289
|
+
...extractOpenApiFields(safeOpenApiMeta),
|
|
300
290
|
};
|
|
301
291
|
}
|
|
302
292
|
schema.properties[propertyName] = swaggerProperty;
|
|
303
293
|
});
|
|
304
|
-
// Handle validation rules
|
|
305
294
|
validationMetadata.forEach((meta) => {
|
|
306
295
|
const propertyName = meta.propertyName;
|
|
296
|
+
// Guard: property might not be in schema if it had no type info
|
|
297
|
+
if (!schema.properties[propertyName]) {
|
|
298
|
+
schema.properties[propertyName] = { type: "string" }; // ✅ safe fallback
|
|
299
|
+
}
|
|
307
300
|
switch (meta.name) {
|
|
308
301
|
case "isNotEmpty":
|
|
309
|
-
if (!schema.required.includes(propertyName)) {
|
|
310
|
-
schema.required.push(propertyName);
|
|
311
|
-
}
|
|
312
|
-
break;
|
|
313
302
|
case "isDefined":
|
|
314
|
-
if (!schema.required.includes(propertyName))
|
|
303
|
+
if (!schema.required.includes(propertyName))
|
|
315
304
|
schema.required.push(propertyName);
|
|
316
|
-
}
|
|
317
305
|
break;
|
|
318
306
|
case "isOptional":
|
|
319
307
|
schema.required = schema.required.filter((item) => item !== propertyName);
|
|
@@ -353,20 +341,46 @@ function generateSwaggerSchema(classType) {
|
|
|
353
341
|
break;
|
|
354
342
|
}
|
|
355
343
|
});
|
|
344
|
+
if (schema.required.length === 0)
|
|
345
|
+
delete schema.required;
|
|
356
346
|
return schema;
|
|
357
347
|
}
|
|
348
|
+
// Build OpenAPI components.schemas from an array of controller/DTO classes
|
|
349
|
+
function generateSwaggerSchema(controllers) {
|
|
350
|
+
if (!Array.isArray(controllers)) {
|
|
351
|
+
return generateClassSchema(controllers);
|
|
352
|
+
}
|
|
353
|
+
const components = {};
|
|
354
|
+
for (const controller of controllers) {
|
|
355
|
+
if (!controller || typeof controller !== "function")
|
|
356
|
+
continue;
|
|
357
|
+
if (!controller.prototype)
|
|
358
|
+
continue;
|
|
359
|
+
// Skip @ApiController classes
|
|
360
|
+
const isController = Reflect.getMetadata(container_1.CONTROLLER_META_KEY, controller);
|
|
361
|
+
if (isController)
|
|
362
|
+
continue;
|
|
363
|
+
// Only include classes explicitly marked with @ApiSchema
|
|
364
|
+
const isSchema = Reflect.getMetadata("openapi:schema", controller);
|
|
365
|
+
if (!isSchema)
|
|
366
|
+
continue;
|
|
367
|
+
components[controller.name] = generateClassSchema(controller);
|
|
368
|
+
}
|
|
369
|
+
return {
|
|
370
|
+
components: Object.keys(components).length > 0
|
|
371
|
+
? { schemas: components }
|
|
372
|
+
: undefined,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
358
375
|
function OpenApiResponse(code = 200, model, description = "Successful response") {
|
|
359
376
|
let dataSchema;
|
|
360
377
|
if (typeof model === "function") {
|
|
361
|
-
|
|
362
|
-
dataSchema = generateSwaggerSchema(model);
|
|
378
|
+
dataSchema = generateClassSchema(model);
|
|
363
379
|
}
|
|
364
380
|
else if (model && typeof model === "object") {
|
|
365
|
-
// Example object
|
|
366
381
|
dataSchema = inferSchemaFromExample(model);
|
|
367
382
|
}
|
|
368
383
|
else {
|
|
369
|
-
// Fallback
|
|
370
384
|
dataSchema = { type: "string" };
|
|
371
385
|
}
|
|
372
386
|
let message = "OK";
|
|
@@ -408,16 +422,10 @@ function OpenApiResponse(code = 200, model, description = "Successful response")
|
|
|
408
422
|
},
|
|
409
423
|
};
|
|
410
424
|
}
|
|
411
|
-
/**
|
|
412
|
-
* Infer a basic JSON schema from a plain JavaScript object.
|
|
413
|
-
*/
|
|
414
425
|
function inferSchemaFromExample(obj) {
|
|
415
426
|
var _a;
|
|
416
427
|
if (Array.isArray(obj)) {
|
|
417
|
-
return {
|
|
418
|
-
type: "array",
|
|
419
|
-
items: inferSchemaFromExample((_a = obj[0]) !== null && _a !== void 0 ? _a : {}),
|
|
420
|
-
};
|
|
428
|
+
return { type: "array", items: inferSchemaFromExample((_a = obj[0]) !== null && _a !== void 0 ? _a : {}) };
|
|
421
429
|
}
|
|
422
430
|
if (obj && typeof obj === "object") {
|
|
423
431
|
const properties = {};
|
|
@@ -428,18 +436,12 @@ function inferSchemaFromExample(obj) {
|
|
|
428
436
|
}
|
|
429
437
|
return inferType(obj);
|
|
430
438
|
}
|
|
431
|
-
/**
|
|
432
|
-
* Infer primitive schema type
|
|
433
|
-
*/
|
|
434
439
|
function inferType(value) {
|
|
435
440
|
const type = typeof value;
|
|
436
441
|
switch (type) {
|
|
437
|
-
case "string":
|
|
438
|
-
|
|
439
|
-
case "
|
|
440
|
-
return { type: "number", example: value };
|
|
441
|
-
case "boolean":
|
|
442
|
-
return { type: "boolean", example: value };
|
|
442
|
+
case "string": return { type: "string", example: value };
|
|
443
|
+
case "number": return { type: "number", example: value };
|
|
444
|
+
case "boolean": return { type: "boolean", example: value };
|
|
443
445
|
case "object":
|
|
444
446
|
if (Array.isArray(value))
|
|
445
447
|
return inferSchemaFromExample(value);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
require("reflect-metadata");
|
|
4
|
-
const swagger_schema_1 = require("./swagger-schema");
|
|
4
|
+
const swagger_schema_1 = require("./swagger-schema"); // ✅ single-class function
|
|
5
5
|
// Mocks for class-validator metadata
|
|
6
6
|
const mockValidationMetadatas = [
|
|
7
7
|
{ propertyName: "name", name: "isNotEmpty", constraints: [] },
|
|
@@ -11,12 +11,21 @@ const mockValidationMetadatas = [
|
|
|
11
11
|
{ propertyName: "desc", name: "minLength", constraints: [5] },
|
|
12
12
|
{ propertyName: "desc", name: "maxLength", constraints: [100] },
|
|
13
13
|
];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
14
|
+
jest.mock("class-validator", () => {
|
|
15
|
+
const mockGetMetadataStorage = jest.fn(() => ({
|
|
16
|
+
getTargetValidationMetadatas: jest.fn(() => [
|
|
17
|
+
{ propertyName: "name", name: "isNotEmpty", constraints: [] },
|
|
18
|
+
{ propertyName: "age", name: "isInt", constraints: [] },
|
|
19
|
+
{ propertyName: "email", name: "isEmail", constraints: [] },
|
|
20
|
+
{ propertyName: "tags", name: "isOptional", constraints: [] },
|
|
21
|
+
{ propertyName: "desc", name: "minLength", constraints: [5] },
|
|
22
|
+
{ propertyName: "desc", name: "maxLength", constraints: [100] },
|
|
23
|
+
]),
|
|
24
|
+
}));
|
|
25
|
+
return {
|
|
26
|
+
getMetadataStorage: mockGetMetadataStorage,
|
|
27
|
+
};
|
|
28
|
+
});
|
|
20
29
|
// Helper to set Reflect metadata for property types and openapi
|
|
21
30
|
function setPropertyMetadata(target, property, type, openApi) {
|
|
22
31
|
Reflect.defineMetadata("design:type", type, target, property);
|
|
@@ -33,9 +42,9 @@ setPropertyMetadata(TestDto.prototype, "email", String);
|
|
|
33
42
|
setPropertyMetadata(TestDto.prototype, "tags", Array);
|
|
34
43
|
setPropertyMetadata(TestDto.prototype, "desc", String, { description: "Description", example: "A desc" });
|
|
35
44
|
setPropertyMetadata(TestDto.prototype, "ignored", String, { exclude: true });
|
|
36
|
-
describe("
|
|
45
|
+
describe("generateClassSchema", () => {
|
|
37
46
|
it("should generate correct schema for class properties and validation", () => {
|
|
38
|
-
const schema = (0, swagger_schema_1.
|
|
47
|
+
const schema = (0, swagger_schema_1.generateClassSchema)(TestDto); // ✅
|
|
39
48
|
expect(schema).toEqual({
|
|
40
49
|
type: "object",
|
|
41
50
|
properties: {
|
|
@@ -72,7 +81,7 @@ describe("generateSwaggerSchema", () => {
|
|
|
72
81
|
allOf: [{ type: "string" }],
|
|
73
82
|
anyOf: [{ type: "string" }],
|
|
74
83
|
});
|
|
75
|
-
const schema = (0, swagger_schema_1.
|
|
84
|
+
const schema = (0, swagger_schema_1.generateClassSchema)(TestDto); // ✅
|
|
76
85
|
expect(schema.properties.desc).toMatchObject({
|
|
77
86
|
description: "desc field",
|
|
78
87
|
example: "example",
|
|
@@ -93,13 +102,24 @@ describe("generateSwaggerSchema", () => {
|
|
|
93
102
|
});
|
|
94
103
|
it("should not include excluded properties", () => {
|
|
95
104
|
setPropertyMetadata(TestDto.prototype, "ignored", String, { exclude: true });
|
|
96
|
-
const schema = (0, swagger_schema_1.
|
|
105
|
+
const schema = (0, swagger_schema_1.generateClassSchema)(TestDto); // ✅
|
|
97
106
|
expect(schema.properties.ignored).toBeUndefined();
|
|
98
107
|
});
|
|
99
108
|
it("should fallback to string type if type is unknown", () => {
|
|
100
109
|
setPropertyMetadata(TestDto.prototype, "unknown", undefined);
|
|
101
110
|
mockValidationMetadatas.push({ propertyName: "unknown", name: "isNotEmpty", constraints: [] });
|
|
102
|
-
const schema = (0, swagger_schema_1.
|
|
111
|
+
const schema = (0, swagger_schema_1.generateClassSchema)(TestDto); // ✅
|
|
103
112
|
expect(schema.properties.unknown.type).toBe("string");
|
|
104
113
|
});
|
|
114
|
+
it("should return empty schema for null or undefined input", () => {
|
|
115
|
+
const schema = (0, swagger_schema_1.generateClassSchema)(null);
|
|
116
|
+
expect(schema).toEqual({ type: "object", properties: {}, required: [] });
|
|
117
|
+
});
|
|
118
|
+
it("should handle array controllers input gracefully", () => {
|
|
119
|
+
// generateSwaggerSchema (array version) should skip non-DTO classes
|
|
120
|
+
// generateClassSchema should never receive an array
|
|
121
|
+
const schema = (0, swagger_schema_1.generateClassSchema)(TestDto);
|
|
122
|
+
expect(schema.type).toBe("object");
|
|
123
|
+
expect(schema.properties).toBeDefined();
|
|
124
|
+
});
|
|
105
125
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const uuid: `${string}-${string}-${string}-${string}-${string}`;
|
|
2
|
+
export type Constructor<T = any> = new (...args: any[]) => T;
|
|
3
|
+
export declare function isConstructor(func: any): boolean;
|
|
4
|
+
export declare function formatUrl(path: string): string;
|
|
5
|
+
export declare function parsedPath(ipath: string): string;
|
|
6
|
+
export interface MatchLocation {
|
|
7
|
+
line: number;
|
|
8
|
+
column: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const getLineNumber: (filePath: string, rpath: string | RegExp) => MatchLocation[] | null;
|
|
11
|
+
export declare function normalizePath(base?: string, subPath?: string): string;
|
|
12
|
+
export declare function extrctParamFromUrl(url: string): {
|
|
13
|
+
key: string;
|
|
14
|
+
required: boolean;
|
|
15
|
+
}[];
|
|
16
|
+
export declare function findDuplicates(arr: string[]): string[];
|
|
17
|
+
export declare function sleep(ms: number): Promise<unknown>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getLineNumber = exports.uuid = void 0;
|
|
7
|
+
exports.isConstructor = isConstructor;
|
|
8
|
+
exports.formatUrl = formatUrl;
|
|
9
|
+
exports.parsedPath = parsedPath;
|
|
10
|
+
exports.normalizePath = normalizePath;
|
|
11
|
+
exports.extrctParamFromUrl = extrctParamFromUrl;
|
|
12
|
+
exports.findDuplicates = findDuplicates;
|
|
13
|
+
exports.sleep = sleep;
|
|
14
|
+
/**
|
|
15
|
+
* @copyright 2024
|
|
16
|
+
* @author Tareq Hossain
|
|
17
|
+
* @email xtrinsic96@gmail.com
|
|
18
|
+
* @url https://github.com/xtareq
|
|
19
|
+
*/
|
|
20
|
+
const fs_1 = __importDefault(require("fs"));
|
|
21
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
22
|
+
exports.uuid = crypto_1.default.randomUUID();
|
|
23
|
+
function isConstructor(func) {
|
|
24
|
+
if (typeof func !== "function") {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (func === Function.prototype.bind || func instanceof RegExp) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (func.prototype && typeof func.prototype === "object") {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const instance = new func();
|
|
35
|
+
return typeof instance === "object";
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function formatUrl(path) {
|
|
42
|
+
if (typeof path !== "string") {
|
|
43
|
+
throw new Error("The path must be a string");
|
|
44
|
+
}
|
|
45
|
+
path = path.trim();
|
|
46
|
+
if (!path.startsWith("/")) {
|
|
47
|
+
path = "/" + path;
|
|
48
|
+
}
|
|
49
|
+
path = path.replace(/\/\/+/g, "/");
|
|
50
|
+
if (path.endsWith("/")) {
|
|
51
|
+
path = path.slice(0, -1);
|
|
52
|
+
}
|
|
53
|
+
return path;
|
|
54
|
+
}
|
|
55
|
+
function parsedPath(ipath) {
|
|
56
|
+
return !ipath.startsWith("/") ? "/" + ipath : ipath;
|
|
57
|
+
}
|
|
58
|
+
const getLineNumber = (filePath, rpath) => {
|
|
59
|
+
var _a;
|
|
60
|
+
let numbers = [];
|
|
61
|
+
try {
|
|
62
|
+
const fileContent = fs_1.default.readFileSync(filePath, "utf8");
|
|
63
|
+
const lines = fileContent.split("\n");
|
|
64
|
+
for (let i = 0; i < lines.length; i++) {
|
|
65
|
+
const match = lines[i].match(rpath);
|
|
66
|
+
if (match) {
|
|
67
|
+
console.log(match);
|
|
68
|
+
numbers.push({
|
|
69
|
+
line: i + 1,
|
|
70
|
+
column: (_a = match.index) !== null && _a !== void 0 ? _a : 0,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return numbers;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return numbers;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
exports.getLineNumber = getLineNumber;
|
|
81
|
+
function normalizePath(base = "/", subPath = "/") {
|
|
82
|
+
return `/${base}/${subPath}`.replace(/\/+/g, "/").replace(/\/$/, "");
|
|
83
|
+
}
|
|
84
|
+
function extrctParamFromUrl(url) {
|
|
85
|
+
const splitPart = url
|
|
86
|
+
.split("/")
|
|
87
|
+
.filter((x) => x.startsWith(":") || x.startsWith("?:"));
|
|
88
|
+
return splitPart.map((f) => ({
|
|
89
|
+
key: f.replace(/(\?|:)/g, ""),
|
|
90
|
+
required: !f.startsWith("?:"),
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
function findDuplicates(arr) {
|
|
94
|
+
const seen = new Set();
|
|
95
|
+
const duplicates = new Set();
|
|
96
|
+
for (const str of arr) {
|
|
97
|
+
if (seen.has(str)) {
|
|
98
|
+
duplicates.add(str);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
seen.add(str);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return Array.from(duplicates);
|
|
105
|
+
}
|
|
106
|
+
function sleep(ms) {
|
|
107
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
108
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function inject<T>(cls: new (...args: any[]) => T): T;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.inject = inject;
|
|
7
|
+
/**
|
|
8
|
+
* @copyright 2024
|
|
9
|
+
* @author Tareq Hossain
|
|
10
|
+
* @email xtrinsic96@gmail.com
|
|
11
|
+
* @url https://github.com/xtareq
|
|
12
|
+
*/
|
|
13
|
+
const container_1 = __importDefault(require("../container"));
|
|
14
|
+
const system_exception_1 = require("../exceptions/system-exception");
|
|
15
|
+
function inject(cls) {
|
|
16
|
+
try {
|
|
17
|
+
return container_1.default.get(cls);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
throw new system_exception_1.SystemUseError("Not a project class. Maybe you wanna register it first.");
|
|
21
|
+
}
|
|
22
|
+
}
|
package/dist/utils/hash.d.ts
CHANGED
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
export declare const hashPasswordSync: (password: string) => string;
|
|
2
|
-
export declare const matchPasswordSync: (password: string, hash: string) => boolean;
|
|
3
1
|
export declare const hashPassword: (password: string) => Promise<string>;
|
|
4
2
|
export declare const matchPassword: (password: string, hash: string) => Promise<boolean>;
|
package/dist/utils/hash.js
CHANGED
|
@@ -3,12 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.matchPassword = exports.hashPassword =
|
|
6
|
+
exports.matchPassword = exports.hashPassword = void 0;
|
|
7
7
|
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
|
8
|
-
const hashPasswordSync = (password) => bcryptjs_1.default.hashSync(password, 12);
|
|
9
|
-
exports.hashPasswordSync = hashPasswordSync;
|
|
10
|
-
const matchPasswordSync = (password, hash) => bcryptjs_1.default.compareSync(password, hash);
|
|
11
|
-
exports.matchPasswordSync = matchPasswordSync;
|
|
12
8
|
const hashPassword = (password) => bcryptjs_1.default.hash(password, 12);
|
|
13
9
|
exports.hashPassword = hashPassword;
|
|
14
10
|
const matchPassword = (password, hash) => bcryptjs_1.default.compare(password, hash);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Constructor } from "./common-utils";
|
|
2
|
+
export declare function pick<T extends object>(obj: T, paths: string[]): Partial<T>;
|
|
3
|
+
export declare function exclude<T extends object>(obj: T | T[], paths: string[]): Partial<T> | Partial<T>[];
|
|
4
|
+
export declare function autoCast(value: any, typeHint?: any, schema?: any): any;
|
|
5
|
+
/**
|
|
6
|
+
* Deeply normalizes query strings into nested JS objects.
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeQueryDeep(query: Record<string, any>): Record<string, any>;
|
|
9
|
+
export declare function transformObjectByInstanceToObject(instance: Constructor, value: object): Record<string, any>;
|
|
10
|
+
export declare function jsonToJs(value: string): any;
|
|
11
|
+
export declare function jsonToInstance(value: string, instance: Constructor): any;
|