zumito-framework 1.5.0 → 1.6.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/dist/ZumitoFramework.js +19 -5
- package/dist/definitions/ErrorType.d.ts +2 -1
- package/dist/definitions/ErrorType.js +2 -1
- package/dist/definitions/Module.d.ts +6 -0
- package/dist/definitions/Module.js +1 -0
- package/dist/modules/core/baseModule/events/discord/MessageCreate.d.ts +0 -9
- package/dist/modules/core/baseModule/events/discord/MessageCreate.js +19 -119
- package/dist/services/ServiceContainer.d.ts +1 -0
- package/dist/services/ServiceContainer.js +4 -0
- package/dist/services/handlers/ErrorHandler.d.ts +10 -1
- package/dist/services/handlers/ErrorHandler.js +7 -0
- package/dist/services/managers/ModuleManager.d.ts +26 -1
- package/dist/services/managers/ModuleManager.js +81 -0
- package/package.json +1 -1
package/dist/ZumitoFramework.js
CHANGED
|
@@ -21,6 +21,8 @@ import { RecursiveObjectMerger } from './services/utilities/RecursiveObjectMerge
|
|
|
21
21
|
import { MemberPermissionChecker } from './services/utilities/MemberPermissionChecker.js';
|
|
22
22
|
import { CommandParser } from './services/CommandParser.js';
|
|
23
23
|
import { SlashCommandRefresher } from './services/SlashCommandRefresher.js';
|
|
24
|
+
import { ErrorHandler } from './services/handlers/ErrorHandler.js';
|
|
25
|
+
import { ErrorType } from './definitions/ErrorType.js';
|
|
24
26
|
// import better-logging
|
|
25
27
|
betterLogging(console);
|
|
26
28
|
/**
|
|
@@ -211,6 +213,21 @@ export class ZumitoFramework {
|
|
|
211
213
|
this.app.use(express.json());
|
|
212
214
|
this.app.use(express.urlencoded({ extended: false }));
|
|
213
215
|
this.app.use(cookieParser());
|
|
216
|
+
//Error handler
|
|
217
|
+
this.app.use(function (err, req, res, next) {
|
|
218
|
+
const errorHandler = ServiceContainer.getService(ErrorHandler);
|
|
219
|
+
errorHandler.handleError(err, {
|
|
220
|
+
type: ErrorType.Api,
|
|
221
|
+
endpoint: req.originalUrl,
|
|
222
|
+
method: req.method,
|
|
223
|
+
});
|
|
224
|
+
if (!res.headersSent) {
|
|
225
|
+
return res.status(500).json({
|
|
226
|
+
error: 'Internal Server Error',
|
|
227
|
+
message: 'An unexpected error occurred. Please try again later.',
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
});
|
|
214
231
|
//this.app.use(express.static(path.join(__dirname, "public")));
|
|
215
232
|
//To allow cross-origin requests
|
|
216
233
|
this.app.use(cors());
|
|
@@ -291,16 +308,13 @@ export class ZumitoFramework {
|
|
|
291
308
|
module = await this.modules.loadModuleFile(path.join(modulesFolder, moduleName));
|
|
292
309
|
}
|
|
293
310
|
// Create module instance
|
|
294
|
-
|
|
295
|
-
// Register module in the framework
|
|
296
|
-
this.modules.registerModule(moduleInstance);
|
|
311
|
+
await this.modules.instanceModule(module, path.join(modulesFolder, moduleName), moduleName);
|
|
297
312
|
}
|
|
298
313
|
async registerBundle(bundlePath, bundleOptions) {
|
|
299
314
|
console.log(bundlePath);
|
|
300
315
|
const bundle = await this.modules.loadModuleFile(bundlePath);
|
|
301
316
|
const bundleName = path.basename(bundlePath);
|
|
302
|
-
|
|
303
|
-
this.modules.registerModule(moduleInstance);
|
|
317
|
+
await this.modules.instanceModule(bundle, bundlePath, bundleName, bundleOptions);
|
|
304
318
|
}
|
|
305
319
|
/**
|
|
306
320
|
* Initializes the Discord client using the Discord.js library.
|
|
@@ -3,5 +3,6 @@ export var ErrorType;
|
|
|
3
3
|
ErrorType[ErrorType["CommandInstance"] = 1] = "CommandInstance";
|
|
4
4
|
ErrorType[ErrorType["CommandLoad"] = 2] = "CommandLoad";
|
|
5
5
|
ErrorType[ErrorType["CommandRun"] = 3] = "CommandRun";
|
|
6
|
-
ErrorType[ErrorType["
|
|
6
|
+
ErrorType[ErrorType["Api"] = 4] = "Api";
|
|
7
|
+
ErrorType[ErrorType["Other"] = 5] = "Other";
|
|
7
8
|
})(ErrorType || (ErrorType = {}));
|
|
@@ -4,6 +4,11 @@ import { FrameworkEvent } from './FrameworkEvent.js';
|
|
|
4
4
|
import { DatabaseModel } from './DatabaseModel.js';
|
|
5
5
|
import { CommandManager } from '../services/managers/CommandManager.js';
|
|
6
6
|
import { ModuleParameters } from './parameters/ModuleParameters.js';
|
|
7
|
+
export declare type ModuleRequeriments = {
|
|
8
|
+
modules: Array<string>;
|
|
9
|
+
services: Array<string>;
|
|
10
|
+
custom: Array<() => Promise<boolean>>;
|
|
11
|
+
};
|
|
7
12
|
export declare abstract class Module {
|
|
8
13
|
protected path: string;
|
|
9
14
|
protected parameters: ModuleParameters;
|
|
@@ -11,6 +16,7 @@ export declare abstract class Module {
|
|
|
11
16
|
protected commands: CommandManager;
|
|
12
17
|
protected events: Map<string, FrameworkEvent>;
|
|
13
18
|
protected models: Array<DatabaseModel>;
|
|
19
|
+
static requeriments: ModuleRequeriments;
|
|
14
20
|
protected commandManager: CommandManager;
|
|
15
21
|
constructor(path: any, parameters?: ModuleParameters);
|
|
16
22
|
initialize(): Promise<void>;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ActionRowBuilder, EmbedBuilder } from 'discord.js';
|
|
2
1
|
import { EventParameters } from '../../../../../definitions/parameters/EventParameters.js';
|
|
3
2
|
import { FrameworkEvent } from '../../../../../definitions/FrameworkEvent.js';
|
|
4
3
|
import { MemberPermissionChecker } from '../../../../../services/utilities/MemberPermissionChecker.js';
|
|
@@ -13,12 +12,4 @@ export declare class MessageCreate extends FrameworkEvent {
|
|
|
13
12
|
constructor();
|
|
14
13
|
execute({ message, framework }: EventParameters): Promise<import("discord.js").Message<boolean>>;
|
|
15
14
|
autocorrect(str: string, words: string[]): any;
|
|
16
|
-
getErrorEmbed(error: any, parse: any): {
|
|
17
|
-
embeds: EmbedBuilder[];
|
|
18
|
-
components: ActionRowBuilder<import("@discordjs/builders").AnyComponentBuilder>[];
|
|
19
|
-
allowedMentions: {
|
|
20
|
-
repliedUser: boolean;
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
parseError(error: any): any;
|
|
24
15
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import ErrorStackParser from 'error-stack-parser';
|
|
1
|
+
import { PermissionsBitField, } from 'discord.js';
|
|
3
2
|
import { FrameworkEvent } from '../../../../../definitions/FrameworkEvent.js';
|
|
4
3
|
import leven from 'leven';
|
|
5
|
-
import path from 'path';
|
|
6
4
|
import { ServiceContainer } from '../../../../../services/ServiceContainer.js';
|
|
7
5
|
import { CommandParser } from '../../../../../services/CommandParser.js';
|
|
8
6
|
import { MemberPermissionChecker } from '../../../../../services/utilities/MemberPermissionChecker.js';
|
|
9
7
|
import { ZumitoFramework } from '../../../../../ZumitoFramework.js';
|
|
10
8
|
import { GuildDataGetter } from '../../../../../services/utilities/GuildDataGetter.js';
|
|
9
|
+
import { ErrorHandler } from '../../../../../services/handlers/ErrorHandler.js';
|
|
10
|
+
import { ErrorType } from '../../../../../definitions/ErrorType.js';
|
|
11
11
|
export class MessageCreate extends FrameworkEvent {
|
|
12
12
|
once = false;
|
|
13
13
|
source = 'discord';
|
|
@@ -114,6 +114,15 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
114
114
|
return framework.translations.get('command.' + commandInstance.name + '.' + key, guildSettings.lang, params);
|
|
115
115
|
}
|
|
116
116
|
},
|
|
117
|
+
}).catch((error) => {
|
|
118
|
+
const errorHandler = ServiceContainer.getService(ErrorHandler);
|
|
119
|
+
errorHandler.handleError(error, {
|
|
120
|
+
command: commandInstance,
|
|
121
|
+
type: ErrorType.CommandRun,
|
|
122
|
+
});
|
|
123
|
+
message.reply({
|
|
124
|
+
content: "An error ocurred while running this command.",
|
|
125
|
+
});
|
|
117
126
|
});
|
|
118
127
|
if (!message.channel.isDMBased && !message.deletable) {
|
|
119
128
|
return; // TODO: test if this works
|
|
@@ -129,21 +138,14 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
129
138
|
}
|
|
130
139
|
}
|
|
131
140
|
catch (error) {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
message: error.message,
|
|
141
|
+
const errorHandler = ServiceContainer.getService(ErrorHandler);
|
|
142
|
+
errorHandler.handleError(error, {
|
|
135
143
|
command: commandInstance,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
catch (e) {
|
|
143
|
-
if (channel.type !== ChannelType.GuildStageVoice) {
|
|
144
|
-
channel.send(content);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
144
|
+
type: ErrorType.CommandRun,
|
|
145
|
+
});
|
|
146
|
+
message.reply({
|
|
147
|
+
content: "An error ocurred while running this command.",
|
|
148
|
+
});
|
|
147
149
|
}
|
|
148
150
|
}
|
|
149
151
|
}
|
|
@@ -164,106 +166,4 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
164
166
|
}
|
|
165
167
|
return bestWord;
|
|
166
168
|
}
|
|
167
|
-
getErrorEmbed(error, parse) {
|
|
168
|
-
let parsedError;
|
|
169
|
-
if (parse) {
|
|
170
|
-
parsedError = this.parseError(error);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
parsedError = error;
|
|
174
|
-
}
|
|
175
|
-
const embed = new EmbedBuilder()
|
|
176
|
-
.setTitle('Error')
|
|
177
|
-
.setDescription('An error has occured while executing this command.')
|
|
178
|
-
.setTimestamp()
|
|
179
|
-
.addFields([
|
|
180
|
-
{
|
|
181
|
-
name: 'Command:',
|
|
182
|
-
value: error.command.name || 'Not defined',
|
|
183
|
-
},
|
|
184
|
-
])
|
|
185
|
-
.addFields([
|
|
186
|
-
{
|
|
187
|
-
name: 'Arguments:',
|
|
188
|
-
value: error.args.toString() || 'None',
|
|
189
|
-
},
|
|
190
|
-
])
|
|
191
|
-
.addFields([
|
|
192
|
-
{
|
|
193
|
-
name: 'Error name:',
|
|
194
|
-
value: error.name || 'Not defined',
|
|
195
|
-
},
|
|
196
|
-
])
|
|
197
|
-
.addFields([
|
|
198
|
-
{
|
|
199
|
-
name: 'Error message:',
|
|
200
|
-
value: error.message || 'Not defined',
|
|
201
|
-
},
|
|
202
|
-
]);
|
|
203
|
-
if (error.possibleSolutions !== undefined) {
|
|
204
|
-
error.possibleSolutions.forEach((solution) => {
|
|
205
|
-
embed.addFields([
|
|
206
|
-
{
|
|
207
|
-
name: 'Posible solution:',
|
|
208
|
-
value: solution,
|
|
209
|
-
},
|
|
210
|
-
]);
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
const stackFrames = ErrorStackParser.parse(error).filter((e) => !e.fileName.includes('node_modules') &&
|
|
214
|
-
!e.fileName.includes('node:internal'));
|
|
215
|
-
let stack = '';
|
|
216
|
-
const path1 = path.resolve('./');
|
|
217
|
-
const path2 = path1.replaceAll('\\', '/');
|
|
218
|
-
stackFrames.forEach((frame) => {
|
|
219
|
-
stack += `[${frame.fileName
|
|
220
|
-
.replace(path1, '')
|
|
221
|
-
.replace(path2, '')
|
|
222
|
-
.replace('file://', '')}:${frame.lineNumber}](https://zumito.ga/redirect?url=vscode://file/${frame.fileName.replace('file://', '')}:${frame.lineNumber}) ${frame.functionName}()\n`;
|
|
223
|
-
});
|
|
224
|
-
if (error.stack !== undefined) {
|
|
225
|
-
embed.addFields([
|
|
226
|
-
{
|
|
227
|
-
name: 'Call stack:',
|
|
228
|
-
value: stack || error.stack || error.stack.toString(),
|
|
229
|
-
},
|
|
230
|
-
]);
|
|
231
|
-
}
|
|
232
|
-
if (error.details !== undefined) {
|
|
233
|
-
error.details.forEach((detail) => {
|
|
234
|
-
embed.addFields([
|
|
235
|
-
{
|
|
236
|
-
name: 'Detail:',
|
|
237
|
-
value: detail,
|
|
238
|
-
},
|
|
239
|
-
]);
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
const body = `\n\n\n---\nComand:\`\`\`${error.command.name || 'not defined'}\`\`\`\nArguments:\`\`\`${error.args.toString() || 'none'}\`\`\`\nError:\`\`\`${error.name || 'not defined'}\`\`\`\nError message:\`\`\`${error.message || 'not defined'}\`\`\`\n`;
|
|
243
|
-
const requestUrl = `https://github.com/ZumitoTeam/Zumito/issues/new?body=${encodeURIComponent(body)}`;
|
|
244
|
-
const row = new ActionRowBuilder().addComponents(new ButtonBuilder()
|
|
245
|
-
.setStyle(ButtonStyle.Link)
|
|
246
|
-
.setLabel('Report error')
|
|
247
|
-
.setEmoji('975645505302437978')
|
|
248
|
-
.setURL(requestUrl));
|
|
249
|
-
return {
|
|
250
|
-
embeds: [embed],
|
|
251
|
-
components: [row],
|
|
252
|
-
allowedMentions: {
|
|
253
|
-
repliedUser: false,
|
|
254
|
-
},
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
parseError(error) {
|
|
258
|
-
error.possibleSolutions = [];
|
|
259
|
-
if (/(?:^|(?<= ))(EmbedBuilder|Discord|ActionRowBuilder|ButtonBuilder|MessageSelectMenu)(?:(?= )|$) is not defined/gm.test(error.message)) {
|
|
260
|
-
error.possibleSolutions.push('const { ' +
|
|
261
|
-
error.message.split(' ')[0] +
|
|
262
|
-
" } = require('discord.js');");
|
|
263
|
-
}
|
|
264
|
-
else if (error.message.includes('A custom id and url cannot both be specified')) {
|
|
265
|
-
error.possibleSolutions.push('Remove .setCustomId(...) or .setURL(...)');
|
|
266
|
-
}
|
|
267
|
-
return error;
|
|
268
|
-
}
|
|
269
169
|
}
|
|
@@ -4,6 +4,7 @@ declare class ServiceContainerManager {
|
|
|
4
4
|
getService<T>(serviceClass: new (...args: any[]) => T | string): T;
|
|
5
5
|
getServiceByName<T>(serviceName: string): T;
|
|
6
6
|
addInstance(serviceClass: any, instance: any): void;
|
|
7
|
+
hasService(serviceClass: any): boolean;
|
|
7
8
|
}
|
|
8
9
|
export declare const ServiceContainer: ServiceContainerManager;
|
|
9
10
|
export {};
|
|
@@ -39,6 +39,10 @@ class ServiceContainerManager {
|
|
|
39
39
|
return;
|
|
40
40
|
this.services.get(serviceName).instance = instance;
|
|
41
41
|
}
|
|
42
|
+
hasService(serviceClass) {
|
|
43
|
+
const serviceName = typeof serviceClass == 'string' ? serviceClass : serviceClass.name;
|
|
44
|
+
return this.services.has(serviceName);
|
|
45
|
+
}
|
|
42
46
|
}
|
|
43
47
|
if (!global.ServiceContainer)
|
|
44
48
|
global.ServiceContainer = new ServiceContainerManager();
|
|
@@ -9,10 +9,19 @@ declare type CommandErrorOptions = BaseErrorOptions & {
|
|
|
9
9
|
type: ErrorType.CommandInstance | ErrorType.CommandLoad | ErrorType.CommandRun;
|
|
10
10
|
command: Command;
|
|
11
11
|
};
|
|
12
|
+
declare type ApiErrorOptions = BaseErrorOptions & {
|
|
13
|
+
type: ErrorType.Api;
|
|
14
|
+
endpoint: string;
|
|
15
|
+
method: string;
|
|
16
|
+
};
|
|
17
|
+
declare type OtherErrorOptions = BaseErrorOptions & {
|
|
18
|
+
type: ErrorType.Other;
|
|
19
|
+
};
|
|
20
|
+
declare type ErrorOptions = CommandErrorOptions | ApiErrorOptions | OtherErrorOptions;
|
|
12
21
|
export declare class ErrorHandler {
|
|
13
22
|
framework: ZumitoFramework;
|
|
14
23
|
constructor(framework: ZumitoFramework);
|
|
15
|
-
handleError(error: any, options:
|
|
24
|
+
handleError(error: any, options: ErrorOptions): void;
|
|
16
25
|
handleCommandError(error: Error, options: CommandErrorOptions): void;
|
|
17
26
|
handleShapeShiftErrors(error: any): void;
|
|
18
27
|
printErrorStack(error: Error): void;
|
|
@@ -22,6 +22,13 @@ export class ErrorHandler {
|
|
|
22
22
|
console.error(`Validation error: ${error.validator} received invalid input: ${error.given}`);
|
|
23
23
|
console.line('');
|
|
24
24
|
}
|
|
25
|
+
else if (options?.type == ErrorType.Api) {
|
|
26
|
+
console.group(`[❌] Error in API endpoint ${options.endpoint} (${options.method})`);
|
|
27
|
+
console.line(chalk.red('Error:'));
|
|
28
|
+
console.line(error.toString());
|
|
29
|
+
console.line('');
|
|
30
|
+
console.groupEnd();
|
|
31
|
+
}
|
|
25
32
|
else {
|
|
26
33
|
console.error(error.toString());
|
|
27
34
|
console.line('');
|
|
@@ -3,6 +3,12 @@ import { Module } from "../../definitions/Module.js";
|
|
|
3
3
|
import { ModuleParameters } from "../../definitions/parameters/ModuleParameters.js";
|
|
4
4
|
export declare class ModuleManager {
|
|
5
5
|
protected modules: Map<string, Module>;
|
|
6
|
+
protected pendingInstancePool: Array<{
|
|
7
|
+
module: any;
|
|
8
|
+
rootPath: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
options?: ModuleParameters;
|
|
11
|
+
}>;
|
|
6
12
|
protected framework: ZumitoFramework;
|
|
7
13
|
constructor(framework: ZumitoFramework);
|
|
8
14
|
set(name: string, module: Module): void;
|
|
@@ -14,5 +20,24 @@ export declare class ModuleManager {
|
|
|
14
20
|
get size(): number;
|
|
15
21
|
loadModuleFile(folderPath: string): Promise<unknown>;
|
|
16
22
|
registerModule(module: InstanceType<typeof Module>): void;
|
|
17
|
-
instanceModule(module: any, rootPath: string, name?: string, options?: ModuleParameters): Promise<Module
|
|
23
|
+
instanceModule(module: any, rootPath: string, name?: string, options?: ModuleParameters): Promise<Module | {
|
|
24
|
+
modules: string[];
|
|
25
|
+
services: string[];
|
|
26
|
+
custom: boolean;
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Comprueba si los requisitos de un módulo están satisfechos antes de instanciarlo.
|
|
30
|
+
* Retorna un array con los requisitos incumplidos.
|
|
31
|
+
* @param moduleClass Clase del módulo (no instancia)
|
|
32
|
+
*/
|
|
33
|
+
checkModuleRequeriments(moduleClass: typeof Module): Promise<{
|
|
34
|
+
modules: string[];
|
|
35
|
+
services: string[];
|
|
36
|
+
custom: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* Intenta inicializar todos los módulos pendientes en la pool, iterando hasta que no queden o no se pueda avanzar más.
|
|
40
|
+
* Evita bucles infinitos si ningún módulo puede ser inicializado en una iteración.
|
|
41
|
+
*/
|
|
42
|
+
initializePendingModules(): Promise<void>;
|
|
18
43
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Module } from "../../definitions/Module.js";
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { ServiceContainer } from "../ServiceContainer.js";
|
|
4
5
|
export class ModuleManager {
|
|
5
6
|
modules;
|
|
7
|
+
pendingInstancePool = [];
|
|
6
8
|
framework;
|
|
7
9
|
constructor(framework) {
|
|
8
10
|
this.modules = new Map();
|
|
@@ -58,6 +60,15 @@ export class ModuleManager {
|
|
|
58
60
|
*/
|
|
59
61
|
}
|
|
60
62
|
async instanceModule(module, rootPath, name, options) {
|
|
63
|
+
// Comprobar requerimientos del módulo
|
|
64
|
+
const unmeetRequeriments = await this.checkModuleRequeriments(module);
|
|
65
|
+
// If there are failed requeriments, put the class into a pool for later retry
|
|
66
|
+
if (unmeetRequeriments.modules.length > 0 || unmeetRequeriments.services.length > 0 || unmeetRequeriments.custom === false) {
|
|
67
|
+
this.pendingInstancePool.push({
|
|
68
|
+
module, rootPath, name, options
|
|
69
|
+
});
|
|
70
|
+
return unmeetRequeriments;
|
|
71
|
+
}
|
|
61
72
|
let moduleInstance;
|
|
62
73
|
if (module.constructor) {
|
|
63
74
|
try {
|
|
@@ -73,6 +84,76 @@ export class ModuleManager {
|
|
|
73
84
|
else {
|
|
74
85
|
//moduleInstance = new Module();
|
|
75
86
|
}
|
|
87
|
+
this.registerModule(moduleInstance);
|
|
76
88
|
return moduleInstance;
|
|
77
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Comprueba si los requisitos de un módulo están satisfechos antes de instanciarlo.
|
|
92
|
+
* Retorna un array con los requisitos incumplidos.
|
|
93
|
+
* @param moduleClass Clase del módulo (no instancia)
|
|
94
|
+
*/
|
|
95
|
+
async checkModuleRequeriments(moduleClass) {
|
|
96
|
+
const requeriments = moduleClass.requeriments;
|
|
97
|
+
const failed = {
|
|
98
|
+
modules: [],
|
|
99
|
+
services: [],
|
|
100
|
+
custom: true
|
|
101
|
+
};
|
|
102
|
+
if (!requeriments) {
|
|
103
|
+
// Si no hay requerimientos definidos, se considera válido
|
|
104
|
+
return failed;
|
|
105
|
+
}
|
|
106
|
+
// Comprobar módulos requeridos
|
|
107
|
+
if (requeriments.modules && requeriments.modules.length > 0) {
|
|
108
|
+
for (const mod of requeriments.modules) {
|
|
109
|
+
if (!this.modules.get(mod))
|
|
110
|
+
failed.modules.push(mod);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Comprobar servicios requeridos
|
|
114
|
+
if (requeriments.services && requeriments.services.length > 0) {
|
|
115
|
+
for (const service of requeriments.services) {
|
|
116
|
+
if (!ServiceContainer.hasService(service))
|
|
117
|
+
failed.services.push(service);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Solo probar custom si los anteriores se cumplieron
|
|
121
|
+
if (failed.services.length === 0 && failed.modules.length == 0 && requeriments.custom && requeriments.custom.length > 0) {
|
|
122
|
+
for (const custom of requeriments.custom) {
|
|
123
|
+
if (!(await custom()))
|
|
124
|
+
failed.custom = false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return failed;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Intenta inicializar todos los módulos pendientes en la pool, iterando hasta que no queden o no se pueda avanzar más.
|
|
131
|
+
* Evita bucles infinitos si ningún módulo puede ser inicializado en una iteración.
|
|
132
|
+
*/
|
|
133
|
+
async initializePendingModules() {
|
|
134
|
+
let initializedInLastIteration;
|
|
135
|
+
do {
|
|
136
|
+
initializedInLastIteration = 0;
|
|
137
|
+
// Copia actual de la pool para iterar
|
|
138
|
+
const poolCopy = [...this.pendingInstancePool];
|
|
139
|
+
this.pendingInstancePool = [];
|
|
140
|
+
for (const pending of poolCopy) {
|
|
141
|
+
const result = await this.instanceModule(pending.module, pending.rootPath, pending.name, pending.options);
|
|
142
|
+
// Si no se pudo inicializar, vuelve a ponerlo en la pool
|
|
143
|
+
if (typeof result !== 'object' || result instanceof Module) {
|
|
144
|
+
initializedInLastIteration++;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
this.pendingInstancePool.push(pending);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} while (this.pendingInstancePool.length > 0 && initializedInLastIteration > 0);
|
|
151
|
+
// Si quedan módulos en la pool, no se pudieron inicializar por dependencias incumplidas
|
|
152
|
+
if (this.pendingInstancePool.length > 0) {
|
|
153
|
+
console.warn(`[📦⚠️] No se pudieron inicializar los siguientes módulos por requerimientos incumplidos:`);
|
|
154
|
+
for (const pending of this.pendingInstancePool) {
|
|
155
|
+
console.warn(`- ${pending.name || pending.module.name}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
78
159
|
}
|