@yumerijs/core 1.1.3 → 1.2.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/core.js CHANGED
@@ -32,14 +32,11 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.Core = void 0;
40
37
  /**
41
- * @time: 2025/07/12 18:14
42
- * @author: FireGuo & Manus
38
+ * @time: 2025/08/14 09:48
39
+ * @author: FireGuo
43
40
  * WindyPear-Team All right reserved
44
41
  **/
45
42
  const yaml = __importStar(require("js-yaml"));
@@ -48,8 +45,10 @@ const path = __importStar(require("path"));
48
45
  const config_1 = require("./config");
49
46
  const logger_1 = require("./logger");
50
47
  const command_1 = require("./command");
51
- const chokidar_1 = __importDefault(require("chokidar"));
48
+ const chokidar = __importStar(require("chokidar"));
49
+ const route_1 = require("./route");
52
50
  const context_1 = require("./context");
51
+ const hook_1 = require("./hook");
53
52
  class Core {
54
53
  plugins = {};
55
54
  config = null;
@@ -57,21 +56,42 @@ class Core {
57
56
  eventListeners = {};
58
57
  components = {};
59
58
  commands = {};
59
+ routes = {};
60
60
  pluginLoader;
61
61
  logger = new logger_1.Logger('core');
62
62
  providedComponents = {};
63
- pluginModules = {};
64
- configPath = '';
65
63
  globalMiddlewares = {};
66
- cmdtoplu = {};
67
- comtoplu = {};
68
- evttoplu = {};
69
- mdwtoplu = {};
70
- plftoplu = {};
71
64
  pluginStatus = {};
65
+ hooks = {};
66
+ pluginWatchers = {};
67
+ pluginModules = {};
68
+ configPath = '';
69
+ /**
70
+ * 插件名 -> Context 映射
71
+ */
72
+ pluginContexts = {};
72
73
  constructor(pluginLoader) {
73
74
  this.pluginLoader = pluginLoader;
74
75
  }
76
+ /**
77
+ * 获取或创建插件对应 Context
78
+ */
79
+ getContext(pluginName) {
80
+ if (!this.pluginContexts[pluginName]) {
81
+ this.pluginContexts[pluginName] = new context_1.Context(this, pluginName);
82
+ }
83
+ return this.pluginContexts[pluginName];
84
+ }
85
+ /**
86
+ * 清理指定插件注册的所有内容
87
+ */
88
+ unregall(pluginName) {
89
+ const ctx = this.pluginContexts[pluginName];
90
+ if (ctx) {
91
+ ctx.dispose();
92
+ delete this.pluginContexts[pluginName];
93
+ }
94
+ }
75
95
  /**
76
96
  * 加载配置文件
77
97
  * @param configPath 配置文件的路径
@@ -96,7 +116,7 @@ class Core {
96
116
  * @param configPath 配置文件的路径
97
117
  */
98
118
  watchConfig(configPath) {
99
- const watcher = chokidar_1.default.watch(configPath, {
119
+ const watcher = chokidar.watch(configPath, {
100
120
  persistent: true,
101
121
  ignoreInitial: true,
102
122
  awaitWriteFinish: {
@@ -143,6 +163,7 @@ class Core {
143
163
  }
144
164
  /**
145
165
  * 加载所有在配置文件中启用的插件
166
+ * @returns Promise<void>
146
167
  */
147
168
  async loadPlugins() {
148
169
  if (!this.config || typeof this.config.plugins !== 'object' || this.config.plugins === null) {
@@ -162,6 +183,13 @@ class Core {
162
183
  }
163
184
  }
164
185
  const enabledPlugins = allPluginNames.filter(name => !name.startsWith('~'));
186
+ // 卸载配置中已禁用或移除的已加载插件
187
+ const currentlyLoaded = Object.keys(this.plugins);
188
+ for (const loadedName of currentlyLoaded) {
189
+ if (!enabledPlugins.includes(loadedName)) {
190
+ await this.unloadPlugin(loadedName);
191
+ }
192
+ }
165
193
  if (enabledPlugins.length === 0) {
166
194
  this.logger.info('No enabled plugins found in configuration.');
167
195
  return;
@@ -189,12 +217,9 @@ class Core {
189
217
  if (pendingPlugins.length > 0) {
190
218
  // this.logger.warn('Some plugins could not be loaded due to unresolved dependencies:', pendingPlugins);
191
219
  }
192
- if (process.env.NODE_ENV === 'development') {
193
- this.watchPlugins(this);
194
- }
195
220
  }
196
221
  /**
197
- * 导出的函数:加载单个插件
222
+ * 加载单个插件
198
223
  * @param pluginName 要加载的插件名
199
224
  * @param triggerPendingCheck 是否在加载后触发对其他待定插件的检查,默认为 true
200
225
  * @returns Promise<boolean> 是否加载成功
@@ -224,7 +249,7 @@ class Core {
224
249
  this.plugins[pluginName] = pluginInstance;
225
250
  if (pluginInstance.apply) {
226
251
  this.pluginLoader.logger.info(`Apply plugin "${pluginName}"`);
227
- await pluginInstance.apply(new context_1.Context(this, pluginName), await this.getPluginConfig(pluginName));
252
+ await pluginInstance.apply(this.getContext(pluginName), await this.getPluginConfig(pluginName));
228
253
  }
229
254
  // 注册提供的组件
230
255
  if (pluginInstance.provide) {
@@ -242,6 +267,30 @@ class Core {
242
267
  if (triggerPendingCheck) {
243
268
  await this._loadPendingPlugins();
244
269
  }
270
+ // In development mode, watch the plugin for changes.
271
+ if (process.env.NODE_ENV === 'development') {
272
+ let pluginPathToWatch = null;
273
+ try {
274
+ const pkgJsonPath = require.resolve(`${pluginName}/package.json`);
275
+ pluginPathToWatch = path.dirname(pkgJsonPath);
276
+ }
277
+ catch (e) {
278
+ const localPluginPath = path.resolve(process.cwd(), pluginName);
279
+ const localPluginPathInPlugins = path.resolve(process.cwd(), 'plugins', pluginName);
280
+ if (fs.existsSync(localPluginPath)) {
281
+ pluginPathToWatch = localPluginPath;
282
+ }
283
+ else if (fs.existsSync(localPluginPathInPlugins)) {
284
+ pluginPathToWatch = localPluginPathInPlugins;
285
+ }
286
+ }
287
+ if (pluginPathToWatch) {
288
+ this.watchPlugin(pluginName, pluginPathToWatch);
289
+ }
290
+ else {
291
+ this.logger.warn(`Could not resolve path for plugin ${pluginName} to watch for changes.`);
292
+ }
293
+ }
245
294
  return true;
246
295
  }
247
296
  catch (err) {
@@ -251,7 +300,8 @@ class Core {
251
300
  }
252
301
  }
253
302
  /**
254
- * 内部函数:尝试加载所有处于 PENDING 状态的插件
303
+ * 尝试加载所有处于 PENDING 状态的插件
304
+ * @returns Promise<void>
255
305
  */
256
306
  async _loadPendingPlugins() {
257
307
  const pendingPlugins = Object.keys(this.pluginStatus).filter(p => this.pluginStatus[p] === "pending" /* PluginStatus.PENDING */);
@@ -298,8 +348,9 @@ class Core {
298
348
  // await this._loadPendingPlugins();
299
349
  }
300
350
  /**
301
- * 内部函数:执行单个插件的卸载逻辑
351
+ * 执行单个插件的卸载逻辑
302
352
  * @param pluginName 插件名
353
+ * @param ispending 是否处于 PENDING 状态
303
354
  */
304
355
  async _unloadSinglePlugin(pluginName, ispending = false) {
305
356
  if (this.pluginStatus[pluginName] !== "enabled" /* PluginStatus.ENABLED */) {
@@ -308,14 +359,18 @@ class Core {
308
359
  this.logger.info(`Unloading plugin "${pluginName}"...`);
309
360
  try {
310
361
  const plugin = this.plugins[pluginName];
311
- if (plugin && plugin.disable) {
312
- await plugin.disable(new context_1.Context(this, pluginName));
313
- }
362
+ if (plugin && plugin.disable)
363
+ await plugin.disable(this.getContext(pluginName));
314
364
  await this.pluginLoader.unloadPlugin(pluginName);
315
365
  this.unregall(pluginName); // 清理该插件注册的所有内容
316
366
  delete this.plugins[pluginName];
317
367
  delete this.pluginModules[pluginName];
318
368
  this.pluginStatus[pluginName] = ispending ? "pending" /* PluginStatus.PENDING */ : "disabled" /* PluginStatus.DISABLED */;
369
+ // Stop watching the plugin directory
370
+ if (this.pluginWatchers[pluginName]) {
371
+ this.pluginWatchers[pluginName].close();
372
+ delete this.pluginWatchers[pluginName];
373
+ }
319
374
  this.emit('plugin-unloaded', pluginName);
320
375
  }
321
376
  catch (error) {
@@ -342,14 +397,17 @@ class Core {
342
397
  }
343
398
  }
344
399
  /**
345
- * 监听插件文件变化,实现热更新
346
- * @param core Core 实例
347
- * @param pluginsDir 插件目录,默认为 'plugins'
400
+ * 监听插件文件变化
401
+ * @param pluginName 插件名称
402
+ * @param pluginPath 插件路径
348
403
  */
349
- watchPlugins(core, pluginsDir = 'plugins') {
404
+ watchPlugin(pluginName, pluginPath) {
405
+ if (this.pluginWatchers[pluginName]) {
406
+ return; // Already watching
407
+ }
350
408
  const logger = new logger_1.Logger('hmr');
351
- const watcher = chokidar_1.default.watch(pluginsDir, {
352
- ignored: /(^|[/\\])\../,
409
+ const watcher = chokidar.watch(pluginPath, {
410
+ ignored: /(^|[\/])\../,
353
411
  persistent: true,
354
412
  ignoreInitial: true,
355
413
  awaitWriteFinish: {
@@ -357,34 +415,20 @@ class Core {
357
415
  pollInterval: 100,
358
416
  },
359
417
  });
360
- const getPluginNameFromPath = (changePath) => {
361
- if (!changePath.endsWith('.ts') && !changePath.endsWith('.js'))
362
- return null;
363
- const parts = changePath.split(path.sep);
364
- return parts.length > 1 ? parts[1] : null;
365
- };
366
418
  watcher.on('change', async (changePath) => {
367
- const pluginName = getPluginNameFromPath(changePath);
368
- if (pluginName) {
369
- logger.info(`Plugin file changed: ${changePath}`);
370
- await core.reloadPlugin(pluginName);
371
- }
419
+ logger.info(`Plugin file changed: ${changePath}`);
420
+ await this.reloadPlugin(pluginName);
372
421
  });
373
422
  watcher.on('add', async (changePath) => {
374
- const pluginName = getPluginNameFromPath(changePath);
375
- if (pluginName) {
376
- logger.info(`New plugin file added: ${changePath}`);
377
- await core.reloadPlugin(pluginName);
378
- }
423
+ logger.info(`New file added to plugin ${pluginName}: ${changePath}`);
424
+ await this.reloadPlugin(pluginName);
379
425
  });
380
426
  watcher.on('unlink', async (changePath) => {
381
- const pluginName = getPluginNameFromPath(changePath);
382
- if (pluginName) {
383
- logger.info(`Plugin file removed: ${changePath}`);
384
- await core.unloadPlugin(pluginName);
385
- }
427
+ logger.info(`File removed from plugin ${pluginName}: ${changePath}`);
428
+ await this.reloadPlugin(pluginName);
386
429
  });
387
- logger.info(`Watching for plugin changes in ${pluginsDir}`);
430
+ this.pluginWatchers[pluginName] = watcher;
431
+ // logger.info(`Watching for changes in plugin: ${pluginName}`);
388
432
  }
389
433
  /**
390
434
  * 注册组件
@@ -414,7 +458,6 @@ class Core {
414
458
  unregisterComponent(name) {
415
459
  delete this.components[name];
416
460
  delete this.providedComponents[name];
417
- delete this.comtoplu[name];
418
461
  }
419
462
  /**
420
463
  * 注册事件监听器
@@ -455,43 +498,101 @@ class Core {
455
498
  return this;
456
499
  }
457
500
  /**
458
- * 注册命令
459
- * @param name 命令名称
460
- * @returns Command 实例
501
+ * @deprecated 已更改为路由
461
502
  */
462
503
  command(name) {
463
504
  const command = new command_1.Command(this, name);
464
505
  this.commands[name] = command;
465
506
  return command;
466
507
  }
508
+ /**
509
+ * 注册路由
510
+ * @param path 路由路径
511
+ * @returns Route 实例
512
+ */
513
+ route(path) {
514
+ const route = new route_1.Route(path);
515
+ this.routes[path] = route;
516
+ return route;
517
+ }
518
+ /**
519
+ * 注册 Hook 钩子
520
+ * @param name Hook 点名称
521
+ * @param hookname 钩子名称
522
+ * @param callback 钩子函数
523
+ */
524
+ hook(name, hookname, callback) {
525
+ if (!this.hooks[name]) {
526
+ this.hooks[name] = new hook_1.Hook(name);
527
+ }
528
+ this.hooks[name].add(hookname, callback);
529
+ }
530
+ /**
531
+ * 消除 Hook 钩子
532
+ */
533
+ unhook(name, hookname) {
534
+ if (this.hooks[name]) {
535
+ this.hooks[name].remove(hookname);
536
+ }
537
+ }
538
+ /**
539
+ * 执行 Hook 钩子
540
+ * @param name Hook 点名称
541
+ * @param args 参数
542
+ * @return Promise<any[]>
543
+ */
544
+ async hookExecute(name, ...args) {
545
+ if (this.hooks[name]) {
546
+ return await this.hooks[name].trigger(...args);
547
+ }
548
+ return [];
549
+ }
467
550
  /**
468
551
  * 执行命令
469
- * @param name 命令名称
470
- * @param session 会话对象
471
- * @param args 传递给命令处理函数的参数
472
- * @returns 会话对象或 null
552
+ * @deprecated
473
553
  */
474
554
  async executeCommand(name, session, ...args) {
475
555
  const command = this.commands[name];
476
556
  if (command) {
477
- const globalMiddlewareList = Object.values(this.globalMiddlewares || {});
478
- const commandMiddlewareList = command.middlewares || [];
479
- const middlewares = [...globalMiddlewareList, ...commandMiddlewareList];
557
+ const middlewares = [...Object.values(this.globalMiddlewares), ...(command.middlewares || [])];
480
558
  let index = 0;
481
559
  const runner = async () => {
482
- if (index < middlewares.length) {
483
- const middleware = middlewares[index++];
484
- await middleware(session, runner);
485
- }
486
- else {
560
+ if (index < middlewares.length)
561
+ await middlewares[index++](session, runner);
562
+ else
487
563
  await command.executeHandler(session, ...args);
488
- }
489
564
  };
490
565
  await runner();
491
566
  return session;
492
567
  }
493
568
  return null;
494
569
  }
570
+ /**
571
+ * 执行路由
572
+ * @param pathname 需要匹配的URL
573
+ * @param session 当前会话
574
+ * @param queryParams URL参数
575
+ * @returns 是否匹配成功
576
+ */
577
+ async executeRoute(pathname, session, queryParams) {
578
+ for (const routePath in this.routes) {
579
+ const route = this.routes[routePath];
580
+ const result = route.match(pathname);
581
+ if (result) {
582
+ const middlewares = [...Object.values(this.globalMiddlewares), ...(route.middlewares || [])];
583
+ let index = 0;
584
+ const runner = async () => {
585
+ if (index < middlewares.length)
586
+ await middlewares[index++](session, runner);
587
+ else
588
+ await route.executeHandler(session, queryParams, result.pathParams);
589
+ };
590
+ await runner();
591
+ return true;
592
+ }
593
+ }
594
+ return false;
595
+ }
495
596
  /**
496
597
  * 注册平台
497
598
  * @param platform 平台实例
@@ -501,44 +602,6 @@ class Core {
501
602
  this.platforms.push(platform);
502
603
  return platform.startPlatform(this);
503
604
  }
504
- /**
505
- * 清理指定插件注册的所有内容
506
- * @param pluginname 插件名称
507
- */
508
- unregall(pluginname) {
509
- // 清理 commands
510
- Object.keys(this.cmdtoplu)
511
- .filter(cmd => this.cmdtoplu[cmd] === pluginname)
512
- .forEach(cmd => {
513
- delete this.cmdtoplu[cmd];
514
- delete this.commands[cmd];
515
- });
516
- // 清理 components 和 providedComponents
517
- Object.keys(this.comtoplu)
518
- .filter(comp => this.comtoplu[comp] === pluginname)
519
- .forEach(comp => {
520
- delete this.comtoplu[comp];
521
- delete this.components[comp];
522
- delete this.providedComponents[comp];
523
- });
524
- // 清理 event listeners
525
- for (const evt in this.evttoplu) {
526
- if (this.evttoplu[evt][pluginname]) {
527
- const pluginListeners = this.evttoplu[evt][pluginname] || [];
528
- if (this.eventListeners[evt]) {
529
- this.eventListeners[evt] = this.eventListeners[evt].filter(l => !pluginListeners.includes(l));
530
- }
531
- delete this.evttoplu[evt][pluginname];
532
- }
533
- }
534
- // 清理 middlewares
535
- Object.keys(this.mdwtoplu)
536
- .filter(mdw => this.mdwtoplu[mdw] === pluginname)
537
- .forEach(mdw => {
538
- delete this.mdwtoplu[mdw];
539
- delete this.globalMiddlewares[mdw];
540
- });
541
- }
542
605
  /**
543
606
  * 获取命令
544
607
  * @param name 命令名称
@@ -547,5 +610,19 @@ class Core {
547
610
  getCommand(name) {
548
611
  return this.commands[name] || null;
549
612
  }
613
+ /**
614
+ * 获取路由
615
+ * @param path 匹配路径
616
+ * @return Route 实例或 false
617
+ */
618
+ getRoute(path) {
619
+ for (const routePath in this.routes) {
620
+ const route = this.routes[routePath];
621
+ if (route.match(path)) {
622
+ return route;
623
+ }
624
+ }
625
+ return false;
626
+ }
550
627
  }
551
628
  exports.Core = Core;
package/dist/hook.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @time: 2025/08/14 18:33
3
+ * @author: FireGuo
4
+ * WindyPear-Team All right reserved
5
+ **/
6
+ /**
7
+ * Hook 处理器
8
+ */
9
+ export type HookHandler = (...args: any[]) => Promise<any>;
10
+ /**
11
+ * Hook 类
12
+ */
13
+ export declare class Hook {
14
+ name: string;
15
+ handlers: Record<string, HookHandler>;
16
+ /**
17
+ * 创建 Hook 实例
18
+ * @param name Hook 名称
19
+ */
20
+ constructor(name: string);
21
+ /**
22
+ * 添加 Hook 函数
23
+ * @param name Hook 函数名称
24
+ * @param handler Hook 函数
25
+ */
26
+ add(name: string, handler: HookHandler): void;
27
+ /**
28
+ * 删除 Hook 函数
29
+ * @param name Hook 函数名称
30
+ */
31
+ remove(name: string): void;
32
+ /**
33
+ * 触发 Hook 函数
34
+ * @param session 会话
35
+ * @param args 参数
36
+ * @returns 执行结果
37
+ */
38
+ trigger(...args: any[]): Promise<any[]>;
39
+ }
package/dist/hook.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * @time: 2025/08/14 18:33
4
+ * @author: FireGuo
5
+ * WindyPear-Team All right reserved
6
+ **/
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Hook = void 0;
9
+ /**
10
+ * Hook 类
11
+ */
12
+ class Hook {
13
+ name;
14
+ handlers = {};
15
+ /**
16
+ * 创建 Hook 实例
17
+ * @param name Hook 名称
18
+ */
19
+ constructor(name) {
20
+ this.name = name;
21
+ }
22
+ /**
23
+ * 添加 Hook 函数
24
+ * @param name Hook 函数名称
25
+ * @param handler Hook 函数
26
+ */
27
+ add(name, handler) {
28
+ this.handlers[name] = handler;
29
+ }
30
+ /**
31
+ * 删除 Hook 函数
32
+ * @param name Hook 函数名称
33
+ */
34
+ remove(name) {
35
+ delete this.handlers[name];
36
+ }
37
+ /**
38
+ * 触发 Hook 函数
39
+ * @param session 会话
40
+ * @param args 参数
41
+ * @returns 执行结果
42
+ */
43
+ async trigger(...args) {
44
+ let result;
45
+ for (const handler of Object.values(this.handlers)) {
46
+ result.push(handler(...args));
47
+ }
48
+ return result;
49
+ }
50
+ }
51
+ exports.Hook = Hook;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  /**
2
- * @time: 2025/03/24 12:26
2
+ * @time: 2025/08/14 09:48
3
3
  * @author: FireGuo
4
4
  * WindyPear-Team All right reserved
5
5
  **/
6
6
  export * from './core';
7
7
  export * from './session';
8
8
  export * from './command';
9
+ export * from './route';
9
10
  export * from './config';
10
11
  export * from './logger';
11
12
  export * from './platform';
12
13
  export * from './context';
14
+ export * from './hook';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * @time: 2025/03/24 12:26
3
+ * @time: 2025/08/14 09:48
4
4
  * @author: FireGuo
5
5
  * WindyPear-Team All right reserved
6
6
  **/
@@ -22,7 +22,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
22
  __exportStar(require("./core"), exports);
23
23
  __exportStar(require("./session"), exports);
24
24
  __exportStar(require("./command"), exports);
25
+ __exportStar(require("./route"), exports);
25
26
  __exportStar(require("./config"), exports);
26
27
  __exportStar(require("./logger"), exports);
27
28
  __exportStar(require("./platform"), exports);
28
29
  __exportStar(require("./context"), exports);
30
+ __exportStar(require("./hook"), exports);
package/dist/logger.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @time: 2025/03/25 18:01
2
+ * @time: 2025/08/14 09:48
3
3
  * @author: FireGuo
4
4
  * WindyPear-Team All right reserved
5
- */
5
+ **/
6
6
  import { Core } from './core';
7
7
  export declare class Logger {
8
8
  private title;
@@ -12,6 +12,7 @@ export declare class Logger {
12
12
  static setCore(core: Core): void;
13
13
  constructor(title: string);
14
14
  private getRandomColor;
15
+ private getTimestamp;
15
16
  private log;
16
17
  info(...args: any[]): void;
17
18
  warn(...args: any[]): void;