@yumerijs/loader 3.1.2 → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -63,6 +63,8 @@ export declare class PluginLoader {
63
63
  private isNpxInvocation;
64
64
  private detectPackageManager;
65
65
  private confirmPluginInstall;
66
+ private isPluginModuleResolvable;
67
+ private installMissingPluginModules;
66
68
  private installMissingPlugin;
67
69
  private importPluginModule;
68
70
  loadModule(pluginName: string): Promise<Plugin>;
package/dist/index.js CHANGED
@@ -153,6 +153,8 @@ export class PluginLoader {
153
153
  this.logger.info('No enabled plugins found in configuration.');
154
154
  return;
155
155
  }
156
+ // Resolve and install every configured plugin before any plugin module is loaded.
157
+ await this.installMissingPluginModules(allEntries.filter(entry => entry.enabled));
156
158
  // 第一阶段:将 optional 与 depend 一样处理,尽量让可选服务先完成加载并注入。
157
159
  while (await this._loadPendingPlugins(true)) {
158
160
  // Continue scanning until no plugin can satisfy all required and optional dependencies.
@@ -414,7 +416,36 @@ export class PluginLoader {
414
416
  readline.close();
415
417
  }
416
418
  }
419
+ isPluginModuleResolvable(moduleName) {
420
+ try {
421
+ import.meta.resolve(moduleName);
422
+ return true;
423
+ }
424
+ catch (error) {
425
+ if (this.isMissingModuleError(error, moduleName))
426
+ return false;
427
+ throw error;
428
+ }
429
+ }
430
+ async installMissingPluginModules(entries) {
431
+ const missingModules = [...new Set(entries.map(entry => entry.moduleName))]
432
+ .filter(moduleName => !this.isPluginModuleResolvable(moduleName));
433
+ for (const moduleName of missingModules) {
434
+ const shouldInstall = await this.confirmPluginInstall(moduleName);
435
+ if (!shouldInstall)
436
+ continue;
437
+ try {
438
+ await this.installMissingPlugin(moduleName);
439
+ }
440
+ catch (error) {
441
+ this.logger.error(`Failed to install missing plugin "${moduleName}":`, error);
442
+ }
443
+ }
444
+ }
417
445
  async installMissingPlugin(moduleName) {
446
+ if (!/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/i.test(moduleName)) {
447
+ throw new Error(`Cannot automatically install invalid package name "${moduleName}".`);
448
+ }
418
449
  const packageManager = this.detectPackageManager();
419
450
  const global = this.isNpxInvocation();
420
451
  const argsByManager = {
@@ -427,21 +458,21 @@ export class PluginLoader {
427
458
  const command = process.platform === 'win32' ? `${packageManager}.cmd` : packageManager;
428
459
  this.logger.info(`Installing missing plugin "${moduleName}" with ${command} ${args.join(' ')}` +
429
460
  (global ? ' (global)' : ''));
461
+ // Windows command shims (for example npm.cmd) require cmd.exe; execFile
462
+ // otherwise fails before the package manager can start with spawn EINVAL.
463
+ if (process.platform === 'win32') {
464
+ await execFileAsync(process.env.ComSpec || 'cmd.exe', [
465
+ '/d',
466
+ '/s',
467
+ '/c',
468
+ `${command} ${args.join(' ')}`,
469
+ ], { cwd: process.cwd() });
470
+ return;
471
+ }
430
472
  await execFileAsync(command, args, { cwd: process.cwd() });
431
473
  }
432
474
  async importPluginModule(moduleName) {
433
- try {
434
- return await import(moduleName);
435
- }
436
- catch (error) {
437
- if (!this.isMissingModuleError(error, moduleName))
438
- throw error;
439
- const shouldInstall = await this.confirmPluginInstall(moduleName);
440
- if (!shouldInstall)
441
- throw error;
442
- await this.installMissingPlugin(moduleName);
443
- return await import(moduleName);
444
- }
475
+ return await import(moduleName);
445
476
  }
446
477
  async loadModule(pluginName) {
447
478
  const entry = this.getPluginEntry(pluginName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yumerijs/loader",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "description": "Module loader for yumeri",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",