@rapidrest/core 1.0.1
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 +23 -0
- package/README.rst +37 -0
- package/dist/lib/AlertUtils.js +239 -0
- package/dist/lib/AlertUtils.js.map +1 -0
- package/dist/lib/ApiError.js +34 -0
- package/dist/lib/ApiError.js.map +1 -0
- package/dist/lib/ClassLoader.js +159 -0
- package/dist/lib/ClassLoader.js.map +1 -0
- package/dist/lib/FileUtils.js +190 -0
- package/dist/lib/FileUtils.js.map +1 -0
- package/dist/lib/JWTUtils.js +111 -0
- package/dist/lib/JWTUtils.js.map +1 -0
- package/dist/lib/Logger.js +28 -0
- package/dist/lib/Logger.js.map +1 -0
- package/dist/lib/MessagingUtils.js +218 -0
- package/dist/lib/MessagingUtils.js.map +1 -0
- package/dist/lib/NotificationsUtils.js +52 -0
- package/dist/lib/NotificationsUtils.js.map +1 -0
- package/dist/lib/OASUtils.js +207 -0
- package/dist/lib/OASUtils.js.map +1 -0
- package/dist/lib/ObjectFactory.js +302 -0
- package/dist/lib/ObjectFactory.js.map +1 -0
- package/dist/lib/ObjectUtils.js +49 -0
- package/dist/lib/ObjectUtils.js.map +1 -0
- package/dist/lib/StringUtils.js +104 -0
- package/dist/lib/StringUtils.js.map +1 -0
- package/dist/lib/TelemetryUtils.js +159 -0
- package/dist/lib/TelemetryUtils.js.map +1 -0
- package/dist/lib/UserUtils.js +138 -0
- package/dist/lib/UserUtils.js.map +1 -0
- package/dist/lib/ValidationUtils.js +130 -0
- package/dist/lib/ValidationUtils.js.map +1 -0
- package/dist/lib/decorators/ObjectDecorators.js +95 -0
- package/dist/lib/decorators/ObjectDecorators.js.map +1 -0
- package/dist/lib/decorators/index.js +2 -0
- package/dist/lib/decorators/index.js.map +1 -0
- package/dist/lib/index.js +18 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/sleep.js +15 -0
- package/dist/lib/sleep.js.map +1 -0
- package/dist/lib/threads/ThreadLogger.js +43 -0
- package/dist/lib/threads/ThreadLogger.js.map +1 -0
- package/dist/lib/threads/ThreadPool.js +270 -0
- package/dist/lib/threads/ThreadPool.js.map +1 -0
- package/dist/lib/threads/ThreadWorker.js +25 -0
- package/dist/lib/threads/ThreadWorker.js.map +1 -0
- package/dist/lib/threads/ThreadWorkerEntry.js +77 -0
- package/dist/lib/threads/ThreadWorkerEntry.js.map +1 -0
- package/dist/lib/threads/index.js +3 -0
- package/dist/lib/threads/index.js.map +1 -0
- package/dist/types/AlertUtils.d.ts +132 -0
- package/dist/types/ApiError.d.ts +13 -0
- package/dist/types/ClassLoader.d.ts +87 -0
- package/dist/types/FileUtils.d.ts +46 -0
- package/dist/types/JWTUtils.d.ts +139 -0
- package/dist/types/Logger.d.ts +7 -0
- package/dist/types/MessagingUtils.d.ts +77 -0
- package/dist/types/NotificationsUtils.d.ts +32 -0
- package/dist/types/OASUtils.d.ts +54 -0
- package/dist/types/ObjectFactory.d.ts +77 -0
- package/dist/types/ObjectUtils.d.ts +17 -0
- package/dist/types/StringUtils.d.ts +52 -0
- package/dist/types/TelemetryUtils.d.ts +84 -0
- package/dist/types/UserUtils.d.ts +61 -0
- package/dist/types/ValidationUtils.d.ts +66 -0
- package/dist/types/decorators/ObjectDecorators.d.ts +55 -0
- package/dist/types/decorators/index.d.ts +1 -0
- package/dist/types/index.d.ts +17 -0
- package/dist/types/sleep.d.ts +5 -0
- package/dist/types/threads/ThreadLogger.d.ts +15 -0
- package/dist/types/threads/ThreadPool.d.ts +115 -0
- package/dist/types/threads/ThreadWorker.d.ts +41 -0
- package/dist/types/threads/ThreadWorkerEntry.d.ts +1 -0
- package/dist/types/threads/index.d.ts +2 -0
- package/docs/Makefile +20 -0
- package/docs/conf.py +58 -0
- package/docs/index.rst +17 -0
- package/docs/make.bat +35 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/README.md +21 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/functions/Config.md +47 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/functions/Destroy.md +27 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/functions/Init.md +33 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/functions/Inject.md +45 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/functions/Logger.md +27 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/functions/Nullable.md +27 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/functions/Validator.md +39 -0
- package/docs/reference/@rapidrest/namespaces/ObjectDecorators/type-aliases/ValidatorFunction.md +31 -0
- package/docs/reference/README.md +73 -0
- package/docs/reference/classes/AlertUtils.md +158 -0
- package/docs/reference/classes/ApiError.md +263 -0
- package/docs/reference/classes/ClassLoader.md +224 -0
- package/docs/reference/classes/Event.md +109 -0
- package/docs/reference/classes/EventUtils.md +123 -0
- package/docs/reference/classes/FileUtils.md +193 -0
- package/docs/reference/classes/JWTUtils.md +91 -0
- package/docs/reference/classes/MessagingUtils.md +145 -0
- package/docs/reference/classes/OASUtils.md +213 -0
- package/docs/reference/classes/ObjectFactory.md +274 -0
- package/docs/reference/classes/ObjectUtils.md +60 -0
- package/docs/reference/classes/StringUtils.md +169 -0
- package/docs/reference/classes/ThreadPool.md +249 -0
- package/docs/reference/classes/ThreadWorker.md +91 -0
- package/docs/reference/classes/UserUtils.md +239 -0
- package/docs/reference/classes/ValidationUtils.md +294 -0
- package/docs/reference/enumerations/AlertPriority.md +61 -0
- package/docs/reference/enumerations/JWTUtilsCompressionMethods.md +21 -0
- package/docs/reference/enumerations/WorkerMessageType.md +43 -0
- package/docs/reference/functions/sleep.md +25 -0
- package/docs/reference/interfaces/Alert.md +101 -0
- package/docs/reference/interfaces/AlertAttachment.md +51 -0
- package/docs/reference/interfaces/AlertClose.md +31 -0
- package/docs/reference/interfaces/AlertUtilsAttachmentOptions.md +42 -0
- package/docs/reference/interfaces/AlertUtilsOptions.md +41 -0
- package/docs/reference/interfaces/InstanceOptions.md +35 -0
- package/docs/reference/interfaces/JWTPayload.md +143 -0
- package/docs/reference/interfaces/JWTUser.md +55 -0
- package/docs/reference/interfaces/JWTUtilsConfig.md +45 -0
- package/docs/reference/interfaces/JWTUtilsPayloadKeyOptions.md +68 -0
- package/docs/reference/interfaces/JWTUtilsPayloadOptions.md +40 -0
- package/docs/reference/interfaces/JWTUtilsPayloadPasswordOptions.md +78 -0
- package/docs/reference/interfaces/NewEvent.md +25 -0
- package/docs/reference/interfaces/OriginSettings.md +25 -0
- package/docs/reference/interfaces/SlackConfig.md +33 -0
- package/docs/reference/interfaces/SmtpAuth.md +25 -0
- package/docs/reference/interfaces/SmtpConfig.md +41 -0
- package/docs/reference/interfaces/Template.md +81 -0
- package/docs/reference/interfaces/TemplateMapBase.md +13 -0
- package/docs/reference/interfaces/TwilioConfig.md +33 -0
- package/docs/reference/interfaces/WorkerMessage.md +31 -0
- package/docs/reference/interfaces/WorkerOptions.md +61 -0
- package/docs/reference/type-aliases/BooleanFunc.md +23 -0
- package/docs/reference/type-aliases/TemplateMap.md +17 -0
- package/docs/reference/type-aliases/WorkerCallback.md +31 -0
- package/docs/reference/variables/Logger.md +21 -0
- package/package.json +96 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2020-2026 Jean-Philippe Steinmetz
|
|
3
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { Logger } from "./Logger.js";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { Axios } from "axios";
|
|
8
|
+
import YAML from "js-yaml";
|
|
9
|
+
const logger = Logger();
|
|
10
|
+
export class OASUtils {
|
|
11
|
+
/**
|
|
12
|
+
* Gets the datastore definition with the specified name.
|
|
13
|
+
*
|
|
14
|
+
* @param spec The OpenAPI specification to search.
|
|
15
|
+
* @param name The name of the datastore to retrieve.
|
|
16
|
+
* @returns The definition for the datastore with the given name if found, otherwise `undefined`.
|
|
17
|
+
*/
|
|
18
|
+
static getDatastore(spec, name) {
|
|
19
|
+
let result = undefined;
|
|
20
|
+
if (spec.components && spec.components["x-datastores"]) {
|
|
21
|
+
result = spec.components["x-datastores"][name];
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Gets the specification object at the specified path.
|
|
27
|
+
*
|
|
28
|
+
* @param {any} spec The OpenAPI specification to reference.
|
|
29
|
+
* @param {string} path The path of the object to retrieve.
|
|
30
|
+
* @returns {any} The object at the specified path if found, otherwise `undefined`.
|
|
31
|
+
*/
|
|
32
|
+
static getObject(spec, path) {
|
|
33
|
+
let result = spec;
|
|
34
|
+
if (path) {
|
|
35
|
+
if (path[0] === "#") {
|
|
36
|
+
path = path.substring(1, path.length);
|
|
37
|
+
}
|
|
38
|
+
if (path[0] === "/") {
|
|
39
|
+
path = path.substring(1, path.length);
|
|
40
|
+
}
|
|
41
|
+
let parts = path.split("/");
|
|
42
|
+
parts.forEach(part => {
|
|
43
|
+
result = result[part];
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
result = undefined;
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the first available response object for a 2XX response as defined by the provided Operation schema object.
|
|
53
|
+
*
|
|
54
|
+
* @param {any} obj The Operation schema object to search.
|
|
55
|
+
*/
|
|
56
|
+
static getResponse(obj) {
|
|
57
|
+
if (obj.responses) {
|
|
58
|
+
for (let status in obj.responses) {
|
|
59
|
+
if (status[0] === "2") {
|
|
60
|
+
for (let type in obj.responses[status]) {
|
|
61
|
+
return obj.responses[status];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns the first available response content object for a 2XX response as defined by the provided Operation schema object.
|
|
70
|
+
*
|
|
71
|
+
* @param {any} obj The Operation schema object to search.
|
|
72
|
+
*/
|
|
73
|
+
static getResponseContent(obj) {
|
|
74
|
+
let result = this.getResponse(obj);
|
|
75
|
+
return result ? result.content : undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Retrieves the schema definition with the given name.
|
|
79
|
+
*
|
|
80
|
+
* @param {any} spec The OpenAPI specification object to reference.
|
|
81
|
+
* @param {string} name The name of the schema to retrieve.
|
|
82
|
+
* @returns {any} The schema definition with the given name.
|
|
83
|
+
*/
|
|
84
|
+
static getSchema(spec, name) {
|
|
85
|
+
if (!spec.components || !spec.components.schemas) {
|
|
86
|
+
throw new Error("Invalid specification. No schemas found.");
|
|
87
|
+
}
|
|
88
|
+
// Perform a case-insensitive search for the schema
|
|
89
|
+
for (const schemaName in spec.components.schemas) {
|
|
90
|
+
if (schemaName.match(new RegExp(name, 'i'))) {
|
|
91
|
+
return spec.components.schemas[schemaName];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Extracts the type information for a given schema Object definition.
|
|
98
|
+
*
|
|
99
|
+
* @param {any} schemaDef The schema definition object to extract type information from.
|
|
100
|
+
* @param {any} spec The entire OpenAPI specification object.
|
|
101
|
+
* @param {Function} convertDataType The function that converts OpenAPI Specification types to native types.
|
|
102
|
+
* @returns {any} A tuple containing the type, subType and subSchemaRef information.
|
|
103
|
+
*/
|
|
104
|
+
static getTypeInfo(schemaDef, spec, convertDataType) {
|
|
105
|
+
if (schemaDef) {
|
|
106
|
+
let result = { type: null, subSchemaRef: null, subType: null };
|
|
107
|
+
if (schemaDef["$ref"]) {
|
|
108
|
+
let realDef = OASUtils.getObject(spec, schemaDef["$ref"]);
|
|
109
|
+
if (realDef) {
|
|
110
|
+
result.subSchemaRef = schemaDef["$ref"];
|
|
111
|
+
result.type = convertDataType("object", null, path.basename(result.subSchemaRef));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (schemaDef["type"] === "array") {
|
|
118
|
+
if (schemaDef["items"]) {
|
|
119
|
+
if (schemaDef.items["$ref"]) {
|
|
120
|
+
let realDef = OASUtils.getObject(spec, schemaDef.items["$ref"]);
|
|
121
|
+
if (realDef) {
|
|
122
|
+
result.subSchemaRef = schemaDef.items["$ref"];
|
|
123
|
+
result.subType = convertDataType(realDef.type, realDef.format, path.basename(result.subSchemaRef));
|
|
124
|
+
result.type = convertDataType("array", result.subType);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
result.format = schemaDef.items.format;
|
|
129
|
+
result.subType = convertDataType(schemaDef.items.type, schemaDef.items.format);
|
|
130
|
+
result.type = convertDataType("array", result.subType);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
throw new Error("Array defined with no items");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (schemaDef["type"] === undefined && schemaDef["enum"]) {
|
|
138
|
+
result.type = "enum";
|
|
139
|
+
result.values = schemaDef["enum"];
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
result.format = schemaDef.format;
|
|
143
|
+
result.type = convertDataType(schemaDef.type, schemaDef.format);
|
|
144
|
+
if (schemaDef.type === "object") {
|
|
145
|
+
result.subSchemaRef = "Object";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Attempts to load the Open API specification at the given path or URL.
|
|
156
|
+
*
|
|
157
|
+
* @param {string} file The path or URL of the OpenAPI Specification file to load.
|
|
158
|
+
* @returns {Promise<any>} A promise whose result will be the loaded OpenAPI Specification as an object.
|
|
159
|
+
*/
|
|
160
|
+
static async loadSpec(file) {
|
|
161
|
+
let apiSpec = null;
|
|
162
|
+
if (fs.existsSync(file)) {
|
|
163
|
+
let fileType = path.extname(file);
|
|
164
|
+
let data = fs.readFileSync(file, "utf8");
|
|
165
|
+
if (fileType === ".yaml") {
|
|
166
|
+
logger.info("Loading YAML: " + file);
|
|
167
|
+
apiSpec = YAML.load(data);
|
|
168
|
+
}
|
|
169
|
+
else if (fileType === ".json") {
|
|
170
|
+
logger.info("Loading JSON: " + file);
|
|
171
|
+
apiSpec = JSON.parse(data);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
throw new Error("Unsupported file type: " + fileType);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if (file.match(new RegExp(/http[s]?:\/\/[a-zA-Z0-9]*\.?[a-z]*.*/))) {
|
|
178
|
+
const axios = new Axios({ baseURL: file });
|
|
179
|
+
const response = await axios.get(file);
|
|
180
|
+
if (response && response.data) {
|
|
181
|
+
if (typeof response.data === "string") {
|
|
182
|
+
// Assume the file is a YAML first. If not we'll try JSON
|
|
183
|
+
try {
|
|
184
|
+
apiSpec = YAML.load(response.data);
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
apiSpec = response.data;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else if (typeof response.data === "object") {
|
|
191
|
+
apiSpec = response.data;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
throw new Error("Cannot parse data : " + response.data);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
throw new Error("File not found: " + file);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
throw new Error("File not found: " + file);
|
|
203
|
+
}
|
|
204
|
+
return apiSpec;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=OASUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OASUtils.js","sourceRoot":"","sources":["../../src/OASUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2020-2026 Jean-Philippe Steinmetz
|
|
3
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
4
|
+
import "reflect-metadata";
|
|
5
|
+
import { Logger } from "./Logger.js";
|
|
6
|
+
import * as uuid from "uuid";
|
|
7
|
+
/**
|
|
8
|
+
* The `ObjectFactory` is a manager for creating objects based on registered
|
|
9
|
+
* class types. This allows for the tracking of multiple instances of objects
|
|
10
|
+
* so that references can be referenced by unique name.
|
|
11
|
+
*
|
|
12
|
+
* @author Jean-Philippe Steinmetz
|
|
13
|
+
*/
|
|
14
|
+
export class ObjectFactory {
|
|
15
|
+
/** A map for string fully qualified class names to their class types. */
|
|
16
|
+
classes = new Map();
|
|
17
|
+
/** The global application configuration object. */
|
|
18
|
+
config;
|
|
19
|
+
/** A map for the unique name to the intance of a particular class type. */
|
|
20
|
+
instances = new Map();
|
|
21
|
+
/** The application logging utility. */
|
|
22
|
+
logger;
|
|
23
|
+
constructor(config, logger) {
|
|
24
|
+
this.config = config;
|
|
25
|
+
this.logger = logger ? logger : Logger();
|
|
26
|
+
// Add ourself so it can be injected/retrieved
|
|
27
|
+
this.instances.set(`${ObjectFactory.name}:default`, this);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Destroys the specified objects. If `undefined` is passed in, all objects managed by the factory are destroyed.
|
|
31
|
+
*/
|
|
32
|
+
async destroy(objs) {
|
|
33
|
+
// If no set of objects was provided we want to destroy everything
|
|
34
|
+
if (!objs) {
|
|
35
|
+
objs = [];
|
|
36
|
+
this.instances.forEach((value, key) => {
|
|
37
|
+
if (!value.name) {
|
|
38
|
+
value.name = key;
|
|
39
|
+
}
|
|
40
|
+
objs.push(value);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// If only a single object was passed in we need to convert this to an array
|
|
45
|
+
if (!Array.isArray(objs)) {
|
|
46
|
+
objs = [objs];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Go through each object and call its destructor, if available
|
|
50
|
+
for (const obj of objs) {
|
|
51
|
+
const name = obj.name ?? obj._name;
|
|
52
|
+
let destroyFunc = undefined;
|
|
53
|
+
let proto = Object.getPrototypeOf(obj);
|
|
54
|
+
while (proto) {
|
|
55
|
+
for (const member of Object.getOwnPropertyNames(proto)) {
|
|
56
|
+
const hasDestructor = Reflect.getMetadata("rrst:destructor", proto, member);
|
|
57
|
+
if (hasDestructor) {
|
|
58
|
+
destroyFunc = obj[member];
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (destroyFunc) {
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
proto = Object.getPrototypeOf(proto);
|
|
66
|
+
}
|
|
67
|
+
if (destroyFunc) {
|
|
68
|
+
try {
|
|
69
|
+
this.logger.debug("Destroying object: " + name);
|
|
70
|
+
const boundFunc = destroyFunc.bind(obj);
|
|
71
|
+
const result = boundFunc();
|
|
72
|
+
if (result instanceof Promise) {
|
|
73
|
+
await result;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
this.logger.error("Failed to destroy object: " + name);
|
|
78
|
+
this.logger.debug(err);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Deletes all instantiated objects.
|
|
85
|
+
*/
|
|
86
|
+
clear() {
|
|
87
|
+
this.instances.clear();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Deletes all instantiated objects and registered class types.
|
|
91
|
+
*/
|
|
92
|
+
clearAll() {
|
|
93
|
+
this.clear();
|
|
94
|
+
this.classes.clear();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Scans the given object for any properties with the `@Inject` decorator and assigns the correct values.
|
|
98
|
+
* @param obj The object to initialize with injected defaults
|
|
99
|
+
*/
|
|
100
|
+
async initialize(obj) {
|
|
101
|
+
let proto = Object.getPrototypeOf(obj);
|
|
102
|
+
while (proto) {
|
|
103
|
+
// Search for each type of injectable property
|
|
104
|
+
for (const member of Object.getOwnPropertyNames(proto)) {
|
|
105
|
+
// Inject @Config
|
|
106
|
+
const injectConfig = Reflect.getMetadata("rrst:injectConfig", proto, member);
|
|
107
|
+
if (injectConfig) {
|
|
108
|
+
const defaultValue = Reflect.getMetadata("rrst:injectConfigDefault", proto, member);
|
|
109
|
+
// If the value is a string, then it must be a path to a specific variable desired
|
|
110
|
+
if (typeof injectConfig === "string") {
|
|
111
|
+
const value = this.config?.get(injectConfig);
|
|
112
|
+
if (value !== undefined) {
|
|
113
|
+
obj[member] = value;
|
|
114
|
+
}
|
|
115
|
+
else if (defaultValue !== undefined) {
|
|
116
|
+
obj[member] = defaultValue;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
throw new Error("No configuration variable is defined at path: " + injectConfig);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// No specific variable is desired, inject the whole config object
|
|
124
|
+
obj[member] = this.config;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Inject @Logger
|
|
128
|
+
const injectLogger = Reflect.getMetadata("rrst:injectLogger", proto, member);
|
|
129
|
+
if (injectLogger) {
|
|
130
|
+
obj[member] = this.logger;
|
|
131
|
+
}
|
|
132
|
+
// Inject @Inject
|
|
133
|
+
const injectObject = Reflect.getMetadata("rrst:injectObject", proto, member);
|
|
134
|
+
if (injectObject) {
|
|
135
|
+
// First register the type just in case it hasn't been done yet
|
|
136
|
+
this.register(injectObject.type);
|
|
137
|
+
// Now retrieve the instance for the given name
|
|
138
|
+
const instance = await this.newInstance(injectObject.type, injectObject.options);
|
|
139
|
+
obj[member] = instance;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
proto = Object.getPrototypeOf(proto);
|
|
143
|
+
}
|
|
144
|
+
// Call any @Init functions
|
|
145
|
+
const initFuncs = this.getInitMethods(obj);
|
|
146
|
+
for (const func of initFuncs) {
|
|
147
|
+
const result = func.bind(obj)();
|
|
148
|
+
if (result instanceof Promise) {
|
|
149
|
+
await result;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return obj;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Searches an object for one or more functions that implement a `@Init` decorator.
|
|
156
|
+
*
|
|
157
|
+
* @param obj The object to search.
|
|
158
|
+
* @returns The list of functions that implements the `@Init` decorator if found, otherwise undefined.
|
|
159
|
+
*/
|
|
160
|
+
getInitMethods(obj) {
|
|
161
|
+
const results = [];
|
|
162
|
+
for (const member in obj) {
|
|
163
|
+
const initialize = Reflect.getMetadata("rrst:initialize", obj, member);
|
|
164
|
+
if (initialize) {
|
|
165
|
+
results.push(obj[member]);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
let proto = Object.getPrototypeOf(obj);
|
|
170
|
+
while (proto) {
|
|
171
|
+
for (const member of Object.getOwnPropertyNames(proto)) {
|
|
172
|
+
const initialize = Reflect.getMetadata("rrst:initialize", proto, member);
|
|
173
|
+
if (initialize) {
|
|
174
|
+
results.push(obj[member]);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
proto = Object.getPrototypeOf(proto);
|
|
179
|
+
}
|
|
180
|
+
return results;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Returns the object instance with the given unique name. Unique names take the form `<ClassName>:<InstanceName>`.
|
|
184
|
+
* It is possible to only specifiy the `<ClassName>`, doing so will automatically look for the `<ClassName>:default`
|
|
185
|
+
* instance or the first found instance of the given type.
|
|
186
|
+
* @param nameOrType The unique name or class type of the object to retrieve.
|
|
187
|
+
* @returns The object instance associated with the given name if found, otherwise `undefined`.
|
|
188
|
+
*/
|
|
189
|
+
// TODO: Investigate name vs fqn
|
|
190
|
+
getInstance(nameOrType) {
|
|
191
|
+
let search = "";
|
|
192
|
+
if (typeof nameOrType === "string") {
|
|
193
|
+
search = nameOrType;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
search =
|
|
197
|
+
nameOrType && nameOrType.name
|
|
198
|
+
? nameOrType.name
|
|
199
|
+
: nameOrType.constructor
|
|
200
|
+
? nameOrType.constructor.name
|
|
201
|
+
: search;
|
|
202
|
+
}
|
|
203
|
+
// Make sure we have a valid type name
|
|
204
|
+
if (!nameOrType) {
|
|
205
|
+
throw new Error("No valid nameOrType was specified.");
|
|
206
|
+
}
|
|
207
|
+
// First search for the exact name or with `:default`
|
|
208
|
+
let result = this.instances.get(search.includes(":") ? search : search + ":default");
|
|
209
|
+
// If we didn't found a result and we weren't given an exact name to search, find the first
|
|
210
|
+
// instance of the class.
|
|
211
|
+
if (!result && !search.includes(":")) {
|
|
212
|
+
for (const key of this.instances.keys()) {
|
|
213
|
+
if (key.startsWith(search + ":")) {
|
|
214
|
+
result = this.instances.get(key);
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return result;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Creates a new instance of the class specified with the provided unique name or type and constructor arguments. If an existing
|
|
223
|
+
* object has already been created with the given name, that instance is returned, otherwise a new instance is created
|
|
224
|
+
* using the provided arguments.
|
|
225
|
+
*
|
|
226
|
+
* @param type The fully qualified name or type of the class to instantiate. If a type is given it's class name will be inferred
|
|
227
|
+
* via the constructor name.
|
|
228
|
+
* @param name The unique name to give the class instance. Set to `undefined` if you wish to force a new object is created.
|
|
229
|
+
* @param initialize Set to `true` to initialize the object after creation, otherwise set to `false`. Default is `true`.
|
|
230
|
+
* @param args The set of constructor arguments to use during construction
|
|
231
|
+
*/
|
|
232
|
+
newInstance(type, options) {
|
|
233
|
+
let name = options?.name || uuid.v4();
|
|
234
|
+
const initialize = options?.initialize !== undefined ? options.initialize : true;
|
|
235
|
+
const args = options?.args || [];
|
|
236
|
+
// If an class type was given extract it's fqn
|
|
237
|
+
const className = typeof type === "string" ? type : type.fqn || type.name || type.constructor.name;
|
|
238
|
+
// Names are namespace specific by type. Prepend the type to the name if not already done.
|
|
239
|
+
if (name && !name.includes(className)) {
|
|
240
|
+
name = `${className}:${name}`;
|
|
241
|
+
}
|
|
242
|
+
// First check to see if an instance was already created for the given name
|
|
243
|
+
if (name && this.instances.has(name)) {
|
|
244
|
+
return this.instances.get(name);
|
|
245
|
+
}
|
|
246
|
+
// Make sure we have a valid type name
|
|
247
|
+
if (!className) {
|
|
248
|
+
throw new Error("No valid type was specified.");
|
|
249
|
+
}
|
|
250
|
+
// Make sure the class has been registered if a type was provided
|
|
251
|
+
if (typeof type !== "string") {
|
|
252
|
+
this.register(type);
|
|
253
|
+
}
|
|
254
|
+
// Look up the class type in our list
|
|
255
|
+
const clazz = this.classes.get(className);
|
|
256
|
+
if (!clazz || !clazz.constructor) {
|
|
257
|
+
throw new Error("No class found with name: " + className);
|
|
258
|
+
}
|
|
259
|
+
// Create the new instance using the provided params
|
|
260
|
+
this.logger.debug(`Creating new instance of class [${className}] with name [${name}]`);
|
|
261
|
+
const instance = new clazz(...args);
|
|
262
|
+
// Also store the fqn for reference
|
|
263
|
+
Object.defineProperty(instance, "_fqn", {
|
|
264
|
+
enumerable: false,
|
|
265
|
+
writable: false,
|
|
266
|
+
value: className,
|
|
267
|
+
});
|
|
268
|
+
// Store the instance in our list of objects
|
|
269
|
+
if (name) {
|
|
270
|
+
// Save the name to the object
|
|
271
|
+
Object.defineProperty(instance, "_name", {
|
|
272
|
+
enumerable: false,
|
|
273
|
+
writable: false,
|
|
274
|
+
value: name,
|
|
275
|
+
});
|
|
276
|
+
this.instances.set(name, instance);
|
|
277
|
+
}
|
|
278
|
+
// Now initialize the object with any injectable defaults. This must happen after we add the instance
|
|
279
|
+
// to our internal map so that circular dependencies due not cause endless cycles of creation/initialization.
|
|
280
|
+
if (initialize) {
|
|
281
|
+
return this.initialize(instance);
|
|
282
|
+
}
|
|
283
|
+
return instance;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Registers the given class type for the provided fully qualified name.
|
|
287
|
+
* @param clazz The class type to register.
|
|
288
|
+
* @param fqn The fully qualified name of the class to register. If not specified, the class name will be used.
|
|
289
|
+
*/
|
|
290
|
+
register(clazz, fqn) {
|
|
291
|
+
const name = fqn ? fqn : clazz.fqn || clazz.name;
|
|
292
|
+
if (!name) {
|
|
293
|
+
this.logger.info(`Unable to register class ${name} for ${clazz}/${fqn}`);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (!this.classes.has(name)) {
|
|
297
|
+
this.logger.info(`Registering class ${name}`);
|
|
298
|
+
this.classes.set(name, clazz);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=ObjectFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObjectFactory.js","sourceRoot":"","sources":["../../src/ObjectFactory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2020-2026 Jean-Philippe Steinmetz
|
|
3
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
4
|
+
import "reflect-metadata";
|
|
5
|
+
/**
|
|
6
|
+
* Utility class for working with objects.
|
|
7
|
+
*
|
|
8
|
+
* @author Jean-Philippe Steinmetz
|
|
9
|
+
*/
|
|
10
|
+
export class ObjectUtils {
|
|
11
|
+
/**
|
|
12
|
+
* Performs validation of the given object or array. Validation is performed by scanning the object class for properties
|
|
13
|
+
* decorated with `@Validator` and executing the provided validation function.
|
|
14
|
+
*
|
|
15
|
+
* @param obj The object or array of objects to validate.
|
|
16
|
+
* @param clazz The class type that contains the validation metadata.
|
|
17
|
+
* @param recurse Set to `true` to validate all child objects.
|
|
18
|
+
*/
|
|
19
|
+
static validate(obj, clazz, recurse) {
|
|
20
|
+
const objs = Array.isArray(obj) ? obj : [obj];
|
|
21
|
+
for (const obj of objs) {
|
|
22
|
+
const metadataObj = !clazz || obj instanceof clazz ? obj : new clazz();
|
|
23
|
+
// Iterate through all properties of the object
|
|
24
|
+
for (const member of Object.getOwnPropertyNames(obj)) {
|
|
25
|
+
if (member === 'constructor')
|
|
26
|
+
continue;
|
|
27
|
+
const nullable = Reflect.getMetadata("rrst:nullable", metadataObj, member);
|
|
28
|
+
// Value of '0' is valid. Don't throw on such values.
|
|
29
|
+
if (!nullable && (obj[member] === null || obj[member] === undefined || obj[member] === "")) {
|
|
30
|
+
throw new Error(`Property ${member} cannot be null.`);
|
|
31
|
+
}
|
|
32
|
+
const validator = Reflect.getMetadata("rrst:validator", metadataObj, member);
|
|
33
|
+
if (validator && obj[member]) {
|
|
34
|
+
try {
|
|
35
|
+
obj[member] = validator(obj[member]);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
throw new Error(`Property ${member} is invalid. ${err.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// If recursion is requested validate the child object
|
|
42
|
+
if (recurse && typeof obj[member] === "object") {
|
|
43
|
+
ObjectUtils.validate(obj[member], recurse);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=ObjectUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObjectUtils.js","sourceRoot":"","sources":["../../src/ObjectUtils.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kDAAkD;AAClD,+EAA+E;AAC/E,OAAO,kBAAkB,CAAC;AAG1B;;;;GAIG;AACH,MAAM,OAAO,WAAW;IACpB;;;;;;;OAOG;IACI,MAAM,CAAC,QAAQ,CAAC,GAAQ,EAAE,KAAW,EAAE,OAAiB;QAC3D,MAAM,IAAI,GAAU,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACrD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,WAAW,GAAQ,CAAC,KAAK,IAAI,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC;YAE5E,+CAA+C;YAC/C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnD,IAAI,MAAM,KAAK,aAAa;oBAAE,SAAS;gBAEvC,MAAM,QAAQ,GAAQ,OAAO,CAAC,WAAW,CAAC,eAAe,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;gBAChF,qDAAqD;gBACrD,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;oBACzF,MAAM,IAAI,KAAK,CAAC,YAAY,MAAM,kBAAkB,CAAC,CAAC;gBAC1D,CAAC;gBAED,MAAM,SAAS,GAAkC,OAAO,CAAC,WAAW,CAAC,gBAAgB,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;gBAC5G,IAAI,SAAS,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC3B,IAAI,CAAC;wBACD,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;oBACzC,CAAC;oBAAC,OAAO,GAAQ,EAAE,CAAC;wBAChB,MAAM,IAAI,KAAK,CAAC,YAAY,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;oBACrE,CAAC;gBACL,CAAC;gBAED,sDAAsD;gBACtD,IAAI,OAAO,IAAI,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;oBAC7C,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;gBAC/C,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;CACJ"}
|