@eggjs/core 6.4.0 → 6.5.0

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.
Files changed (44) hide show
  1. package/README.md +22 -22
  2. package/dist/commonjs/egg.d.ts +17 -18
  3. package/dist/commonjs/egg.js +11 -11
  4. package/dist/commonjs/lifecycle.d.ts +2 -2
  5. package/dist/commonjs/lifecycle.js +16 -13
  6. package/dist/commonjs/loader/context_loader.js +2 -2
  7. package/dist/commonjs/loader/egg_loader.d.ts +13 -13
  8. package/dist/commonjs/loader/egg_loader.js +77 -62
  9. package/dist/commonjs/loader/file_loader.d.ts +3 -3
  10. package/dist/commonjs/loader/file_loader.js +22 -24
  11. package/dist/commonjs/singleton.d.ts +2 -2
  12. package/dist/commonjs/singleton.js +6 -7
  13. package/dist/commonjs/utils/index.d.ts +2 -2
  14. package/dist/commonjs/utils/index.js +4 -4
  15. package/dist/commonjs/utils/sequencify.d.ts +1 -1
  16. package/dist/commonjs/utils/sequencify.js +18 -13
  17. package/dist/commonjs/utils/timing.js +14 -8
  18. package/dist/esm/egg.d.ts +17 -18
  19. package/dist/esm/egg.js +13 -13
  20. package/dist/esm/lifecycle.d.ts +2 -2
  21. package/dist/esm/lifecycle.js +16 -13
  22. package/dist/esm/loader/context_loader.js +2 -2
  23. package/dist/esm/loader/egg_loader.d.ts +13 -13
  24. package/dist/esm/loader/egg_loader.js +80 -65
  25. package/dist/esm/loader/file_loader.d.ts +3 -3
  26. package/dist/esm/loader/file_loader.js +23 -25
  27. package/dist/esm/singleton.d.ts +2 -2
  28. package/dist/esm/singleton.js +6 -7
  29. package/dist/esm/utils/index.d.ts +2 -2
  30. package/dist/esm/utils/index.js +4 -4
  31. package/dist/esm/utils/sequencify.d.ts +1 -1
  32. package/dist/esm/utils/sequencify.js +18 -13
  33. package/dist/esm/utils/timing.js +14 -8
  34. package/dist/package.json +1 -1
  35. package/package.json +16 -6
  36. package/src/egg.ts +161 -61
  37. package/src/lifecycle.ts +72 -33
  38. package/src/loader/context_loader.ts +9 -7
  39. package/src/loader/egg_loader.ts +445 -183
  40. package/src/loader/file_loader.ts +78 -37
  41. package/src/singleton.ts +64 -26
  42. package/src/utils/index.ts +20 -13
  43. package/src/utils/sequencify.ts +50 -15
  44. package/src/utils/timing.ts +27 -13
@@ -2,39 +2,52 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import assert from 'node:assert';
4
4
  import { debuglog, inspect } from 'node:util';
5
+
5
6
  import { homedir } from 'node-homedir';
6
- import { isAsyncFunction, isClass, isGeneratorFunction, isObject, isPromise } from 'is-type-of';
7
- import type { Logger } from 'egg-logger';
8
7
  import {
9
- getParamNames, readJSONSync, readJSON, exists,
10
- } from 'utility';
8
+ isAsyncFunction,
9
+ isClass,
10
+ isGeneratorFunction,
11
+ isObject,
12
+ isPromise,
13
+ } from 'is-type-of';
14
+ import type { Logger } from 'egg-logger';
15
+ import { getParamNames, readJSONSync, readJSON, exists } from 'utility';
11
16
  import { extend } from 'extend2';
12
- import { Request, Response, Application, Context as KoaContext } from '@eggjs/koa';
17
+ import {
18
+ Request,
19
+ Response,
20
+ Application,
21
+ Context as KoaContext,
22
+ } from '@eggjs/koa';
13
23
  import { register as tsconfigPathsRegister } from 'tsconfig-paths';
14
24
  import { isESM, isSupportTypeScript } from '@eggjs/utils';
15
25
  import { pathMatching, type PathMatchingOptions } from 'egg-path-matching';
16
26
  import { now, diff } from 'performance-ms';
17
- import { CaseStyle, FULLPATH, FileLoader, FileLoaderOptions } from './file_loader.js';
18
- import { ContextLoader, ContextLoaderOptions } from './context_loader.js';
19
- import utils, { Fun } from '../utils/index.js';
20
- import sequencify from '../utils/sequencify.js';
27
+
28
+ import {
29
+ type FileLoaderOptions,
30
+ CaseStyle,
31
+ FULLPATH,
32
+ FileLoader,
33
+ } from './file_loader.js';
34
+ import { type ContextLoaderOptions, ContextLoader } from './context_loader.js';
35
+ import utils, { type Fun } from '../utils/index.js';
36
+ import { sequencify } from '../utils/sequencify.js';
21
37
  import { Timing } from '../utils/timing.js';
22
- import type {
23
- Context, EggCore, MiddlewareFunc,
24
- } from '../egg.js';
38
+ import type { Context, EggCore, MiddlewareFunc } from '../egg.js';
25
39
  import type { BaseContextClass } from '../base_context_class.js';
26
40
  import type { EggAppConfig, EggAppInfo, EggPluginInfo } from '../types.js';
27
41
 
28
42
  const debug = debuglog('@eggjs/core/loader/egg_loader');
29
43
 
30
- const originalPrototypes: Record<string, any> = {
44
+ const originalPrototypes: Record<string, unknown> = {
31
45
  request: Request.prototype,
32
46
  response: Response.prototype,
33
47
  context: KoaContext.prototype,
34
48
  application: Application.prototype,
35
49
  };
36
50
 
37
-
38
51
  export interface EggLoaderOptions {
39
52
  /** server env */
40
53
  env: string;
@@ -80,7 +93,10 @@ export class EggLoader {
80
93
  */
81
94
  constructor(options: EggLoaderOptions) {
82
95
  this.options = options;
83
- assert(fs.existsSync(this.options.baseDir), `${this.options.baseDir} not exists`);
96
+ assert(
97
+ fs.existsSync(this.options.baseDir),
98
+ `${this.options.baseDir} not exists`
99
+ );
84
100
  assert(this.options.app, 'options.app is required');
85
101
  assert(this.options.logger, 'options.logger is required');
86
102
 
@@ -95,15 +111,20 @@ export class EggLoader {
95
111
 
96
112
  // auto require('tsconfig-paths/register') on typescript app
97
113
  // support env.EGG_TYPESCRIPT = true or { "egg": { "typescript": true } } on package.json
98
- if (process.env.EGG_TYPESCRIPT === 'true' || (this.pkg.egg && this.pkg.egg.typescript)) {
114
+ if (
115
+ process.env.EGG_TYPESCRIPT === 'true' ||
116
+ (this.pkg.egg && this.pkg.egg.typescript)
117
+ ) {
99
118
  // skip require tsconfig-paths if tsconfig.json not exists
100
119
  const tsConfigFile = path.join(this.options.baseDir, 'tsconfig.json');
101
120
  if (fs.existsSync(tsConfigFile)) {
102
- tsconfigPathsRegister({ cwd: this.options.baseDir } as any);
121
+ // @ts-expect-error only cwd is required
122
+ tsconfigPathsRegister({ cwd: this.options.baseDir });
103
123
  } else {
104
124
  this.logger.info(
105
125
  '[@eggjs/core/egg_loader] skip register "tsconfig-paths" because tsconfig.json not exists at %s',
106
- tsConfigFile);
126
+ tsConfigFile
127
+ );
107
128
  }
108
129
  }
109
130
 
@@ -143,9 +164,7 @@ export class EggLoader {
143
164
  * @member {String} EggLoader#serverScope
144
165
  * @see AppInfo#serverScope
145
166
  */
146
- this.serverScope = options.serverScope !== undefined
147
- ? options.serverScope
148
- : this.getServerScope();
167
+ this.serverScope = options.serverScope ?? this.getServerScope();
149
168
 
150
169
  /**
151
170
  * @member {AppInfo} EggLoader#appInfo
@@ -168,7 +187,7 @@ export class EggLoader {
168
187
 
169
188
  /**
170
189
  * Get {@link AppInfo#env}
171
- * @return {String} env
190
+ * @returns {String} env
172
191
  * @see AppInfo#env
173
192
  * @private
174
193
  * @since 1.0.0
@@ -185,7 +204,10 @@ export class EggLoader {
185
204
  serverEnv = process.env.EGG_SERVER_ENV;
186
205
  }
187
206
 
188
- if (!serverEnv) {
207
+ if (serverEnv) {
208
+ serverEnv = serverEnv.trim();
209
+ } else {
210
+ // oxlint-disable-next-line eslint/no-lonely-if
189
211
  if (process.env.NODE_ENV === 'test') {
190
212
  serverEnv = 'unittest';
191
213
  } else if (process.env.NODE_ENV === 'production') {
@@ -193,8 +215,6 @@ export class EggLoader {
193
215
  } else {
194
216
  serverEnv = 'local';
195
217
  }
196
- } else {
197
- serverEnv = serverEnv.trim();
198
218
  }
199
219
 
200
220
  return serverEnv;
@@ -202,16 +222,16 @@ export class EggLoader {
202
222
 
203
223
  /**
204
224
  * Get {@link AppInfo#scope}
205
- * @return {String} serverScope
225
+ * @returns {String} serverScope
206
226
  * @private
207
227
  */
208
228
  protected getServerScope(): string {
209
- return process.env.EGG_SERVER_SCOPE || '';
229
+ return process.env.EGG_SERVER_SCOPE ?? '';
210
230
  }
211
231
 
212
232
  /**
213
233
  * Get {@link AppInfo#name}
214
- * @return {String} appname
234
+ * @returns {String} appname
215
235
  * @private
216
236
  * @since 1.0.0
217
237
  */
@@ -226,7 +246,7 @@ export class EggLoader {
226
246
 
227
247
  /**
228
248
  * Get home directory
229
- * @return {String} home directory
249
+ * @returns {String} home directory
230
250
  * @since 3.4.0
231
251
  */
232
252
  getHomedir(): string {
@@ -236,7 +256,7 @@ export class EggLoader {
236
256
 
237
257
  /**
238
258
  * Get app info
239
- * @return {AppInfo} appInfo
259
+ * @returns {AppInfo} appInfo
240
260
  * @since 1.0.0
241
261
  */
242
262
  protected getAppInfo(): EggAppInfo {
@@ -312,7 +332,7 @@ export class EggLoader {
312
332
 
313
333
  /**
314
334
  * Get {@link EggLoader#eggPaths}
315
- * @return {Array} framework directories
335
+ * @returns {Array} framework directories
316
336
  * @see {@link EggLoader#eggPaths}
317
337
  * @private
318
338
  * @since 1.0.0
@@ -340,7 +360,10 @@ export class EggLoader {
340
360
  // }
341
361
  continue;
342
362
  }
343
- assert(typeof eggPath === 'string', 'Symbol.for(\'egg#eggPath\') should be string');
363
+ assert(
364
+ typeof eggPath === 'string',
365
+ "Symbol.for('egg#eggPath') should be string"
366
+ );
344
367
  assert(fs.existsSync(eggPath), `${eggPath} not exists`);
345
368
  const realpath = fs.realpathSync(eggPath);
346
369
  if (!eggPaths.includes(realpath)) {
@@ -433,8 +456,12 @@ export class EggLoader {
433
456
 
434
457
  // disable the plugin that not match the serverEnv
435
458
  if (env && plugin.env.length > 0 && !plugin.env.includes(env)) {
436
- this.logger.info('[@eggjs/core] Plugin %o is disabled by env unmatched, require env(%o) but got env is %o',
437
- name, plugin.env, env);
459
+ this.logger.info(
460
+ '[@eggjs/core] Plugin %o is disabled by env unmatched, require env(%o) but got env is %o',
461
+ name,
462
+ plugin.env,
463
+ env
464
+ );
438
465
  plugin.enable = false;
439
466
  continue;
440
467
  }
@@ -446,7 +473,11 @@ export class EggLoader {
446
473
  }
447
474
 
448
475
  // retrieve the ordered plugins
449
- this.orderPlugins = this.getOrderPlugins(plugins, enabledPluginNames, this.appPlugins);
476
+ this.orderPlugins = this.getOrderPlugins(
477
+ plugins,
478
+ enabledPluginNames,
479
+ this.appPlugins
480
+ );
450
481
 
451
482
  const enablePlugins: Record<string, EggPluginInfo> = {};
452
483
  for (const plugin of this.orderPlugins) {
@@ -465,16 +496,26 @@ export class EggLoader {
465
496
 
466
497
  protected async loadAppPlugins() {
467
498
  // loader plugins from application
468
- const appPlugins = await this.readPluginConfigs(path.join(this.options.baseDir, 'config/plugin.default'));
469
- debug('Loaded app plugins: %j', Object.keys(appPlugins).map(k => `${k}:${appPlugins[k].enable}`));
499
+ const appPlugins = await this.readPluginConfigs(
500
+ path.join(this.options.baseDir, 'config/plugin.default')
501
+ );
502
+ debug(
503
+ 'Loaded app plugins: %j',
504
+ Object.keys(appPlugins).map(k => `${k}:${appPlugins[k].enable}`)
505
+ );
470
506
  return appPlugins;
471
507
  }
472
508
 
473
509
  protected async loadEggPlugins() {
474
510
  // loader plugins from framework
475
- const eggPluginConfigPaths = this.eggPaths.map(eggPath => path.join(eggPath, 'config/plugin.default'));
511
+ const eggPluginConfigPaths = this.eggPaths.map(eggPath =>
512
+ path.join(eggPath, 'config/plugin.default')
513
+ );
476
514
  const eggPlugins = await this.readPluginConfigs(eggPluginConfigPaths);
477
- debug('Loaded egg plugins: %j', Object.keys(eggPlugins).map(k => `${k}:${eggPlugins[k].enable}`));
515
+ debug(
516
+ 'Loaded egg plugins: %j',
517
+ Object.keys(eggPlugins).map(k => `${k}:${eggPlugins[k].enable}`)
518
+ );
478
519
  return eggPlugins;
479
520
  }
480
521
 
@@ -515,7 +556,7 @@ export class EggLoader {
515
556
  */
516
557
  protected async readPluginConfigs(configPaths: string[] | string) {
517
558
  if (!Array.isArray(configPaths)) {
518
- configPaths = [ configPaths ];
559
+ configPaths = [configPaths];
519
560
  }
520
561
 
521
562
  // Get all plugin configurations
@@ -537,14 +578,19 @@ export class EggLoader {
537
578
 
538
579
  // let plugin.js compatible
539
580
  if (configPath.endsWith('plugin.default') && !filepath) {
540
- filepath = this.resolveModule(configPath.replace(/plugin\.default$/, 'plugin'));
581
+ filepath = this.resolveModule(
582
+ configPath.replace(/plugin\.default$/, 'plugin')
583
+ );
541
584
  }
542
585
 
543
586
  if (!filepath) {
544
587
  continue;
545
588
  }
546
589
 
547
- const config = await utils.loadFile(filepath) as Record<string, EggPluginInfo>;
590
+ const config = (await utils.loadFile(filepath)) as Record<
591
+ string,
592
+ EggPluginInfo
593
+ >;
548
594
  for (const name in config) {
549
595
  this.#normalizePluginConfig(config, name, filepath);
550
596
  }
@@ -554,7 +600,11 @@ export class EggLoader {
554
600
  return plugins;
555
601
  }
556
602
 
557
- #normalizePluginConfig(plugins: Record<string, EggPluginInfo | boolean>, name: string, configPath: string) {
603
+ #normalizePluginConfig(
604
+ plugins: Record<string, EggPluginInfo | boolean>,
605
+ name: string,
606
+ configPath: string
607
+ ) {
558
608
  const plugin = plugins[name];
559
609
 
560
610
  // plugin_name: false
@@ -593,7 +643,7 @@ export class EggLoader {
593
643
  async #mergePluginConfig(plugin: EggPluginInfo) {
594
644
  let pkg;
595
645
  let config;
596
- const pluginPackage = path.join(plugin.path!, 'package.json');
646
+ const pluginPackage = path.join(plugin.path as string, 'package.json');
597
647
  if (await utils.existsPath(pluginPackage)) {
598
648
  pkg = await readJSON(pluginPackage);
599
649
  config = pkg.eggPlugin;
@@ -601,25 +651,32 @@ export class EggLoader {
601
651
  plugin.version = pkg.version;
602
652
  }
603
653
  // support commonjs and esm dist files
604
- plugin.path = await this.#formatPluginPathFromPackageJSON(plugin.path!, pkg);
654
+ plugin.path = await this.#formatPluginPathFromPackageJSON(
655
+ plugin.path as string,
656
+ pkg
657
+ );
605
658
  }
606
659
 
607
660
  const logger = this.options.logger;
608
661
  if (!config) {
609
- logger.warn(`[@eggjs/core/egg_loader] pkg.eggPlugin is missing in ${pluginPackage}`);
662
+ logger.warn(
663
+ `[@eggjs/core/egg_loader] pkg.eggPlugin is missing in ${pluginPackage}`
664
+ );
610
665
  return;
611
666
  }
612
667
 
613
668
  if (config.name && config.strict !== false && config.name !== plugin.name) {
614
669
  // pluginName is configured in config/plugin.js
615
670
  // pluginConfigName is pkg.eggPlugin.name
616
- logger.warn(`[@eggjs/core/egg_loader] pluginName(${plugin.name}) is different from pluginConfigName(${config.name})`);
671
+ logger.warn(
672
+ `[@eggjs/core/egg_loader] pluginName(${plugin.name}) is different from pluginConfigName(${config.name})`
673
+ );
617
674
  }
618
675
 
619
676
  // dep compatible
620
677
  depCompatible(config);
621
678
 
622
- for (const key of [ 'dependencies', 'optionalDependencies', 'env' ]) {
679
+ for (const key of ['dependencies', 'optionalDependencies', 'env']) {
623
680
  const values = config[key];
624
681
  const existsValues = Reflect.get(plugin, key);
625
682
  if (Array.isArray(values) && !existsValues?.length) {
@@ -628,10 +685,13 @@ export class EggLoader {
628
685
  }
629
686
  }
630
687
 
631
- protected getOrderPlugins(allPlugins: Record<string, EggPluginInfo>, enabledPluginNames: string[],
632
- appPlugins: Record<string, EggPluginInfo>) {
688
+ protected getOrderPlugins(
689
+ allPlugins: Record<string, EggPluginInfo>,
690
+ enabledPluginNames: string[],
691
+ appPlugins: Record<string, EggPluginInfo>
692
+ ) {
633
693
  // no plugins enabled
634
- if (!enabledPluginNames.length) {
694
+ if (enabledPluginNames.length === 0) {
635
695
  return [];
636
696
  }
637
697
 
@@ -639,9 +699,10 @@ export class EggLoader {
639
699
  debug('Got plugins %j after sequencify', result);
640
700
 
641
701
  // catch error when result.sequence is empty
642
- if (!result.sequence.length) {
702
+ if (result.sequence.length === 0) {
643
703
  const err = new Error(
644
- `sequencify plugins has problem, missing: [${result.missingTasks}], recursive: [${result.recursiveDependencies}]`);
704
+ `sequencify plugins has problem, missing: [${result.missingTasks}], recursive: [${result.recursiveDependencies}]`
705
+ );
645
706
  // find plugins which is required by the missing plugin
646
707
  for (const missName of result.missingTasks) {
647
708
  const requires = [];
@@ -660,7 +721,7 @@ export class EggLoader {
660
721
  // log the plugins that be enabled implicitly
661
722
  const implicitEnabledPlugins: string[] = [];
662
723
  const requireMap: Record<string, string[]> = {};
663
- result.sequence.forEach(name => {
724
+ for (const name of result.sequence) {
664
725
  for (const depName of allPlugins[name].dependencies) {
665
726
  if (!requireMap[depName]) {
666
727
  requireMap[depName] = [];
@@ -673,9 +734,9 @@ export class EggLoader {
673
734
  allPlugins[name].enable = true;
674
735
  allPlugins[name].implicitEnable = true;
675
736
  }
676
- });
737
+ }
677
738
 
678
- for (const [ name, dependents ] of Object.entries(requireMap)) {
739
+ for (const [name, dependents] of Object.entries(requireMap)) {
679
740
  // note:`dependents` will not includes `optionalDependencies`
680
741
  allPlugins[name].dependents = dependents;
681
742
  }
@@ -684,21 +745,25 @@ export class EggLoader {
684
745
  // - configclient required by [rpcClient]
685
746
  // - monitor required by [rpcClient]
686
747
  // - diamond required by [rpcClient]
687
- if (implicitEnabledPlugins.length) {
748
+ if (implicitEnabledPlugins.length > 0) {
688
749
  let message = implicitEnabledPlugins
689
750
  .map(name => ` - ${name} required by [${requireMap[name]}]`)
690
751
  .join('\n');
691
- this.options.logger.info(`Following plugins will be enabled implicitly.\n${message}`);
752
+ this.options.logger.info(
753
+ `Following plugins will be enabled implicitly.\n${message}`
754
+ );
692
755
 
693
756
  // should warn when the plugin is disabled by app
694
757
  const disabledPlugins = implicitEnabledPlugins.filter(
695
- name => appPlugins[name] && appPlugins[name].enable === false);
696
- if (disabledPlugins.length) {
758
+ name => appPlugins[name] && appPlugins[name].enable === false
759
+ );
760
+ if (disabledPlugins.length > 0) {
697
761
  message = disabledPlugins
698
762
  .map(name => ` - ${name} required by [${requireMap[name]}]`)
699
763
  .join('\n');
700
764
  this.options.logger.warn(
701
- `Following plugins will be enabled implicitly that is disabled by application.\n${message}`);
765
+ `Following plugins will be enabled implicitly that is disabled by application.\n${message}`
766
+ );
702
767
  }
703
768
  }
704
769
 
@@ -730,8 +795,10 @@ export class EggLoader {
730
795
  }
731
796
 
732
797
  if (plugin.package) {
733
- assert(isValidatePackageName(plugin.package),
734
- `plugin ${plugin.name} invalid, use 'path' instead of package: "${plugin.package}"`);
798
+ assert(
799
+ isValidatePackageName(plugin.package),
800
+ `plugin ${plugin.name} invalid, use 'path' instead of package: "${plugin.package}"`
801
+ );
735
802
  }
736
803
  return this.#resolvePluginPath(plugin);
737
804
  }
@@ -745,25 +812,33 @@ export class EggLoader {
745
812
  // 'node_modules/.pnpm/yadan@2.0.0/node_modules', <- this is the sibling directory
746
813
  // 'node_modules/.pnpm/egg@2.33.1/node_modules/egg/node_modules',
747
814
  // 'node_modules/.pnpm/egg@2.33.1/node_modules', <- this is the sibling directory
748
- const pluginPkgFile = utils.resolvePath(`${name}/package.json`, { paths: [ ...this.lookupDirs ] });
815
+ const pluginPkgFile = utils.resolvePath(`${name}/package.json`, {
816
+ paths: [...this.lookupDirs],
817
+ });
749
818
  return path.dirname(pluginPkgFile);
750
819
  } catch (err) {
751
820
  debug('[resolvePluginPath] error: %o, plugin info: %o', err, plugin);
752
- throw new Error(`Can not find plugin ${name} in "${[ ...this.lookupDirs ].join(', ')}"`, {
753
- cause: err,
754
- });
821
+ throw new Error(
822
+ `Can not find plugin ${name} in "${[...this.lookupDirs].join(', ')}"`,
823
+ {
824
+ cause: err,
825
+ }
826
+ );
755
827
  }
756
828
  }
757
829
 
758
- async #formatPluginPathFromPackageJSON(pluginPath: string, pluginPkg: {
759
- eggPlugin?: {
760
- exports?: {
761
- import?: string;
762
- require?: string;
763
- typescript?: string;
830
+ async #formatPluginPathFromPackageJSON(
831
+ pluginPath: string,
832
+ pluginPkg: {
833
+ eggPlugin?: {
834
+ exports?: {
835
+ import?: string;
836
+ require?: string;
837
+ typescript?: string;
838
+ };
764
839
  };
765
- };
766
- }): Promise<string> {
840
+ }
841
+ ): Promise<string> {
767
842
  let realPluginPath = pluginPath;
768
843
  const exports = pluginPkg.eggPlugin?.exports;
769
844
  if (exports) {
@@ -771,23 +846,29 @@ export class EggLoader {
771
846
  if (exports.import) {
772
847
  realPluginPath = path.join(pluginPath, exports.import);
773
848
  }
774
- } else {
775
- if (exports.require) {
776
- realPluginPath = path.join(pluginPath, exports.require);
777
- }
849
+ } else if (exports.require) {
850
+ realPluginPath = path.join(pluginPath, exports.require);
778
851
  }
779
- if (exports.typescript && isSupportTypeScript()) {
780
- if (!(await exists(realPluginPath))) {
781
- // if require/import path not exists, use typescript path for development stage
782
- realPluginPath = path.join(pluginPath, exports.typescript);
783
- debug('[formatPluginPathFromPackageJSON] use typescript path %o', realPluginPath);
784
- }
852
+ if (
853
+ exports.typescript &&
854
+ isSupportTypeScript() &&
855
+ !(await exists(realPluginPath))
856
+ ) {
857
+ // if require/import path not exists, use typescript path for development stage
858
+ realPluginPath = path.join(pluginPath, exports.typescript);
859
+ debug(
860
+ '[formatPluginPathFromPackageJSON] use typescript path %o',
861
+ realPluginPath
862
+ );
785
863
  }
786
864
  }
787
865
  return realPluginPath;
788
866
  }
789
867
 
790
- #extendPlugins(targets: Record<string, EggPluginInfo>, plugins: Record<string, EggPluginInfo>) {
868
+ #extendPlugins(
869
+ targets: Record<string, EggPluginInfo>,
870
+ plugins: Record<string, EggPluginInfo>
871
+ ) {
791
872
  if (!plugins) {
792
873
  return;
793
874
  }
@@ -795,21 +876,30 @@ export class EggLoader {
795
876
  const plugin = plugins[name];
796
877
  let targetPlugin = targets[name];
797
878
  if (!targetPlugin) {
798
- targetPlugin = targets[name] = {} as EggPluginInfo;
879
+ targetPlugin = {} as EggPluginInfo;
880
+ targets[name] = targetPlugin;
799
881
  }
800
882
  if (targetPlugin.package && targetPlugin.package === plugin.package) {
801
- this.logger.warn('[@eggjs/core] plugin %s has been defined that is %j, but you define again in %s',
802
- name, targetPlugin, plugin.from);
883
+ this.logger.warn(
884
+ '[@eggjs/core] plugin %s has been defined that is %j, but you define again in %s',
885
+ name,
886
+ targetPlugin,
887
+ plugin.from
888
+ );
803
889
  }
804
890
  if (plugin.path || plugin.package) {
805
891
  delete targetPlugin.path;
806
892
  delete targetPlugin.package;
807
893
  }
808
- for (const [ prop, value ] of Object.entries(plugin)) {
894
+ for (const [prop, value] of Object.entries(plugin)) {
809
895
  if (value === undefined) {
810
896
  continue;
811
897
  }
812
- if (Reflect.get(targetPlugin, prop) && Array.isArray(value) && !value.length) {
898
+ if (
899
+ Reflect.get(targetPlugin, prop) &&
900
+ Array.isArray(value) &&
901
+ value.length === 0
902
+ ) {
813
903
  continue;
814
904
  }
815
905
  Reflect.set(targetPlugin, prop, value);
@@ -852,11 +942,20 @@ export class EggLoader {
852
942
  for (const unit of this.getLoadUnits()) {
853
943
  const isApp = unit.type === 'app';
854
944
  const config = await this.#loadConfig(
855
- unit.path, filename, isApp ? undefined : appConfig, unit.type);
945
+ unit.path,
946
+ filename,
947
+ isApp ? undefined : appConfig,
948
+ unit.type
949
+ );
856
950
  if (!config) {
857
951
  continue;
858
952
  }
859
- debug('[loadConfig] Loaded config %s/%s, %j', unit.path, filename, config);
953
+ debug(
954
+ '[loadConfig] Loaded config %s/%s, %j',
955
+ unit.path,
956
+ filename,
957
+ config
958
+ );
860
959
  extend(true, target, config);
861
960
  }
862
961
  }
@@ -867,8 +966,13 @@ export class EggLoader {
867
966
  extend(true, target, envConfig);
868
967
 
869
968
  // You can manipulate the order of app.config.coreMiddleware and app.config.appMiddleware in app.js
870
- target.coreMiddleware = target.coreMiddlewares = target.coreMiddleware || [];
871
- target.appMiddleware = target.appMiddlewares = target.middleware || [];
969
+ target.coreMiddleware = target.coreMiddleware || [];
970
+ // alias for coreMiddleware
971
+ target.coreMiddlewares = target.coreMiddleware;
972
+
973
+ target.appMiddleware = target.middleware || [];
974
+ // alias for appMiddleware
975
+ target.appMiddlewares = target.appMiddleware;
872
976
 
873
977
  this.config = target;
874
978
  debug('[loadConfig] all config: %o', this.config);
@@ -876,13 +980,15 @@ export class EggLoader {
876
980
  }
877
981
 
878
982
  async #preloadAppConfig() {
879
- const names = [
880
- 'config.default',
881
- `config.${this.serverEnv}`,
882
- ];
983
+ const names = ['config.default', `config.${this.serverEnv}`];
883
984
  const target: Record<string, any> = {};
884
985
  for (const filename of names) {
885
- const config = await this.#loadConfig(this.options.baseDir, filename, undefined, 'app');
986
+ const config = await this.#loadConfig(
987
+ this.options.baseDir,
988
+ filename,
989
+ undefined,
990
+ 'app'
991
+ );
886
992
  if (!config) {
887
993
  continue;
888
994
  }
@@ -891,7 +997,12 @@ export class EggLoader {
891
997
  return target;
892
998
  }
893
999
 
894
- async #loadConfig(dirpath: string, filename: string, extraInject: object | undefined, type: EggDirInfoType) {
1000
+ async #loadConfig(
1001
+ dirpath: string,
1002
+ filename: string,
1003
+ extraInject: object | undefined,
1004
+ type: EggDirInfoType
1005
+ ) {
895
1006
  const isPlugin = type === 'plugin';
896
1007
  const isApp = type === 'app';
897
1008
 
@@ -900,16 +1011,26 @@ export class EggLoader {
900
1011
  if (filename === 'config.default' && !filepath) {
901
1012
  filepath = this.resolveModule(path.join(dirpath, 'config/config'));
902
1013
  }
903
- const config: Record<string, any> = await this.loadFile(filepath!, this.appInfo, extraInject);
1014
+ if (!filepath) {
1015
+ return;
1016
+ }
1017
+ const config: Record<string, any> = await this.loadFile(
1018
+ filepath,
1019
+ this.appInfo,
1020
+ extraInject
1021
+ );
904
1022
  if (!config) return;
905
1023
  if (isPlugin || isApp) {
906
- assert(!config.coreMiddleware, 'Can not define coreMiddleware in app or plugin');
1024
+ assert(
1025
+ !config.coreMiddleware,
1026
+ 'Can not define coreMiddleware in app or plugin'
1027
+ );
907
1028
  }
908
1029
  if (!isApp) {
909
1030
  assert(!config.middleware, 'Can not define middleware in ' + filepath);
910
1031
  }
911
1032
  // store config meta, check where is the property of config come from.
912
- this.#setConfigMeta(config, filepath!);
1033
+ this.#setConfigMeta(config, filepath);
913
1034
  return config;
914
1035
  }
915
1036
 
@@ -917,15 +1038,18 @@ export class EggLoader {
917
1038
  const envConfigStr = process.env.EGG_APP_CONFIG;
918
1039
  if (!envConfigStr) return;
919
1040
  try {
920
- const envConfig: Record<string, any> = JSON.parse(envConfigStr);
1041
+ const envConfig: Record<string, unknown> = JSON.parse(envConfigStr);
921
1042
  this.#setConfigMeta(envConfig, '<process.env.EGG_APP_CONFIG>');
922
1043
  return envConfig;
923
- } catch (err) {
924
- this.options.logger.warn('[egg-loader] process.env.EGG_APP_CONFIG is not invalid JSON: %s', envConfigStr);
1044
+ } catch {
1045
+ this.options.logger.warn(
1046
+ '[egg-loader] process.env.EGG_APP_CONFIG is not invalid JSON: %s',
1047
+ envConfigStr
1048
+ );
925
1049
  }
926
1050
  }
927
1051
 
928
- #setConfigMeta(config: Record<string, any>, filepath: string) {
1052
+ #setConfigMeta(config: Record<string, unknown>, filepath: string) {
929
1053
  config = extend(true, {}, config);
930
1054
  this.#setConfig(config, filepath);
931
1055
  extend(true, this.configMeta, config);
@@ -935,11 +1059,20 @@ export class EggLoader {
935
1059
  for (const key of Object.keys(obj)) {
936
1060
  const val = obj[key];
937
1061
  // ignore console
938
- if (key === 'console' && val && typeof val.Console === 'function' && val.Console === console.Console) {
1062
+ if (
1063
+ key === 'console' &&
1064
+ val &&
1065
+ typeof val.Console === 'function' &&
1066
+ val.Console === console.Console
1067
+ ) {
939
1068
  obj[key] = filepath;
940
1069
  continue;
941
1070
  }
942
- if (val && Object.getPrototypeOf(val) === Object.prototype && Object.keys(val).length > 0) {
1071
+ if (
1072
+ val &&
1073
+ Object.getPrototypeOf(val) === Object.prototype &&
1074
+ Object.keys(val).length > 0
1075
+ ) {
943
1076
  this.#setConfig(val, filepath);
944
1077
  continue;
945
1078
  }
@@ -1010,11 +1143,13 @@ export class EggLoader {
1010
1143
  * can be override in top level framework to support load `app/extends/{name}.js`
1011
1144
  *
1012
1145
  * @param {String} name - filename which may be `app/extend/{name}.js`
1013
- * @return {Array} filepaths extend file paths
1146
+ * @returns {Array} filepaths extend file paths
1014
1147
  * @private
1015
1148
  */
1016
1149
  protected getExtendFilePaths(name: string): string[] {
1017
- return this.getLoadUnits().map(unit => path.join(unit.path, 'app/extend', name));
1150
+ return this.getLoadUnits().map(unit =>
1151
+ path.join(unit.path, 'app/extend', name)
1152
+ );
1018
1153
  }
1019
1154
 
1020
1155
  /**
@@ -1029,7 +1164,8 @@ export class EggLoader {
1029
1164
  // All extend files
1030
1165
  const filepaths = this.getExtendFilePaths(name);
1031
1166
  // if use mm.env and serverEnv is not unittest
1032
- const needUnittest = 'EGG_MOCK_SERVER_ENV' in process.env && this.serverEnv !== 'unittest';
1167
+ const needUnittest =
1168
+ 'EGG_MOCK_SERVER_ENV' in process.env && this.serverEnv !== 'unittest';
1033
1169
  const length = filepaths.length;
1034
1170
  for (let i = 0; i < length; i++) {
1035
1171
  const filepath = filepaths[i];
@@ -1042,15 +1178,19 @@ export class EggLoader {
1042
1178
 
1043
1179
  const mergeRecord = new Map();
1044
1180
  for (const rawFilepath of filepaths) {
1045
- const filepath = this.resolveModule(rawFilepath)!;
1181
+ const filepath = this.resolveModule(rawFilepath);
1046
1182
  if (!filepath) {
1047
1183
  // debug('loadExtend %o not found', rawFilepath);
1048
1184
  continue;
1049
1185
  }
1050
1186
  if (filepath.endsWith('/index.js')) {
1051
- this.app.deprecate(`app/extend/${name}/index.js is deprecated, use app/extend/${name}.js instead`);
1187
+ this.app.deprecate(
1188
+ `app/extend/${name}/index.js is deprecated, use app/extend/${name}.js instead`
1189
+ );
1052
1190
  } else if (filepath.endsWith('/index.ts')) {
1053
- this.app.deprecate(`app/extend/${name}/index.ts is deprecated, use app/extend/${name}.ts instead`);
1191
+ this.app.deprecate(
1192
+ `app/extend/${name}/index.ts is deprecated, use app/extend/${name}.ts instead`
1193
+ );
1054
1194
  }
1055
1195
 
1056
1196
  let ext = await this.requireFile(filepath);
@@ -1059,23 +1199,36 @@ export class EggLoader {
1059
1199
  ext = ext.prototype;
1060
1200
  }
1061
1201
  const properties = Object.getOwnPropertyNames(ext)
1062
- .concat(Object.getOwnPropertySymbols(ext) as any[])
1202
+ .concat(Object.getOwnPropertySymbols(ext) as unknown as string[])
1063
1203
  .filter(name => name !== 'constructor'); // ignore class constructor for extend
1064
1204
 
1065
1205
  for (const property of properties) {
1066
1206
  if (mergeRecord.has(property)) {
1067
- debug('Property: "%s" already exists in "%s",it will be redefined by "%s"',
1068
- property, mergeRecord.get(property), filepath);
1207
+ debug(
1208
+ 'Property: "%s" already exists in "%s",it will be redefined by "%s"',
1209
+ property,
1210
+ mergeRecord.get(property),
1211
+ filepath
1212
+ );
1069
1213
  }
1070
1214
 
1071
1215
  // Copy descriptor
1072
- let descriptor = Object.getOwnPropertyDescriptor(ext, property);
1073
- let originalDescriptor = Object.getOwnPropertyDescriptor(proto, property);
1216
+ let descriptor = Object.getOwnPropertyDescriptor(
1217
+ ext,
1218
+ property
1219
+ ) as PropertyDescriptor;
1220
+ let originalDescriptor = Object.getOwnPropertyDescriptor(
1221
+ proto,
1222
+ property
1223
+ );
1074
1224
  if (!originalDescriptor) {
1075
1225
  // try to get descriptor from originalPrototypes
1076
1226
  const originalProto = originalPrototypes[name];
1077
1227
  if (originalProto) {
1078
- originalDescriptor = Object.getOwnPropertyDescriptor(originalProto, property);
1228
+ originalDescriptor = Object.getOwnPropertyDescriptor(
1229
+ originalProto,
1230
+ property
1231
+ );
1079
1232
  }
1080
1233
  }
1081
1234
  if (originalDescriptor) {
@@ -1090,7 +1243,7 @@ export class EggLoader {
1090
1243
  descriptor.get = originalDescriptor.get;
1091
1244
  }
1092
1245
  }
1093
- Object.defineProperty(proto, property, descriptor!);
1246
+ Object.defineProperty(proto, property, descriptor);
1094
1247
  mergeRecord.set(property, filepath);
1095
1248
  }
1096
1249
  debug('merge %j to %s from %s', properties, name, filepath);
@@ -1164,7 +1317,10 @@ export class EggLoader {
1164
1317
  this.lifecycle.addFunctionAsBootHook(bootHook, bootFilePath);
1165
1318
  debug('[loadBootHook] add bootHookFunction from %o', bootFilePath);
1166
1319
  } else {
1167
- this.options.logger.warn('[@eggjs/core/egg_loader] %s must exports a boot class', bootFilePath);
1320
+ this.options.logger.warn(
1321
+ '[@eggjs/core/egg_loader] %s must exports a boot class',
1322
+ bootFilePath
1323
+ );
1168
1324
  }
1169
1325
  }
1170
1326
  // init boots
@@ -1183,7 +1339,9 @@ export class EggLoader {
1183
1339
  async loadService(options?: Partial<ContextLoaderOptions>) {
1184
1340
  this.timing.start('Load Service');
1185
1341
  // 载入到 app.serviceClasses
1186
- const servicePaths = this.getLoadUnits().map(unit => path.join(unit.path, 'app/service'));
1342
+ const servicePaths = this.getLoadUnits().map(unit =>
1343
+ path.join(unit.path, 'app/service')
1344
+ );
1187
1345
  options = {
1188
1346
  call: true,
1189
1347
  caseStyle: CaseStyle.lower,
@@ -1192,7 +1350,11 @@ export class EggLoader {
1192
1350
  ...options,
1193
1351
  };
1194
1352
  debug('[loadService] options: %o', options);
1195
- await this.loadToContext(servicePaths, 'service', options as ContextLoaderOptions);
1353
+ await this.loadToContext(
1354
+ servicePaths,
1355
+ 'service',
1356
+ options as ContextLoaderOptions
1357
+ );
1196
1358
  this.timing.end('Load Service');
1197
1359
  }
1198
1360
  /** end Service loader */
@@ -1222,7 +1384,9 @@ export class EggLoader {
1222
1384
  const app = this.app;
1223
1385
 
1224
1386
  // load middleware to app.middleware
1225
- const middlewarePaths = this.getLoadUnits().map(unit => path.join(unit.path, 'app/middleware'));
1387
+ const middlewarePaths = this.getLoadUnits().map(unit =>
1388
+ path.join(unit.path, 'app/middleware')
1389
+ );
1226
1390
  opt = {
1227
1391
  call: false,
1228
1392
  override: true,
@@ -1230,7 +1394,11 @@ export class EggLoader {
1230
1394
  directory: middlewarePaths,
1231
1395
  ...opt,
1232
1396
  };
1233
- await this.loadToApp(middlewarePaths, 'middlewares', opt as FileLoaderOptions);
1397
+ await this.loadToApp(
1398
+ middlewarePaths,
1399
+ 'middlewares',
1400
+ opt as FileLoaderOptions
1401
+ );
1234
1402
 
1235
1403
  for (const name in app.middlewares) {
1236
1404
  Object.defineProperty(app.middleware, name, {
@@ -1242,11 +1410,19 @@ export class EggLoader {
1242
1410
  });
1243
1411
  }
1244
1412
 
1245
- this.options.logger.info('Use coreMiddleware order: %j', this.config.coreMiddleware);
1246
- this.options.logger.info('Use appMiddleware order: %j', this.config.appMiddleware);
1413
+ this.options.logger.info(
1414
+ 'Use coreMiddleware order: %j',
1415
+ this.config.coreMiddleware
1416
+ );
1417
+ this.options.logger.info(
1418
+ 'Use appMiddleware order: %j',
1419
+ this.config.appMiddleware
1420
+ );
1247
1421
 
1248
1422
  // use middleware ordered by app.config.coreMiddleware and app.config.appMiddleware
1249
- const middlewareNames = this.config.coreMiddleware.concat(this.config.appMiddleware);
1423
+ const middlewareNames = this.config.coreMiddleware.concat(
1424
+ this.config.appMiddleware
1425
+ );
1250
1426
  debug('[loadMiddleware] middlewareNames: %j', middlewareNames);
1251
1427
  const middlewaresMap = new Map<string, boolean>();
1252
1428
  for (const name of middlewareNames) {
@@ -1260,10 +1436,15 @@ export class EggLoader {
1260
1436
  middlewaresMap.set(name, true);
1261
1437
  const options = this.config[name] || {};
1262
1438
  let mw: MiddlewareFunc | null = createMiddleware(options, app);
1263
- assert(typeof mw === 'function', `Middleware ${name} must be a function, but actual is ${inspect(mw)}`);
1439
+ assert(
1440
+ typeof mw === 'function',
1441
+ `Middleware ${name} must be a function, but actual is ${inspect(mw)}`
1442
+ );
1264
1443
  if (isGeneratorFunction(mw)) {
1265
1444
  const fullpath = Reflect.get(createMiddleware, FULLPATH);
1266
- throw new TypeError(`Support for generators was removed, middleware: ${name}, fullpath: ${fullpath}`);
1445
+ throw new TypeError(
1446
+ `Support for generators was removed, middleware: ${name}, fullpath: ${fullpath}`
1447
+ );
1267
1448
  }
1268
1449
  mw._name = name;
1269
1450
  // middlewares support options.enable, options.ignore and options.match
@@ -1274,14 +1455,27 @@ export class EggLoader {
1274
1455
  mw = debugMiddlewareWrapper(mw);
1275
1456
  }
1276
1457
  app.use(mw);
1277
- debug('[loadMiddleware] Use middleware: %s with options: %j', name, options);
1278
- this.options.logger.info('[@eggjs/core/egg_loader] Use middleware: %s', name);
1458
+ debug(
1459
+ '[loadMiddleware] Use middleware: %s with options: %j',
1460
+ name,
1461
+ options
1462
+ );
1463
+ this.options.logger.info(
1464
+ '[@eggjs/core/egg_loader] Use middleware: %s',
1465
+ name
1466
+ );
1279
1467
  } else {
1280
- this.options.logger.info('[@eggjs/core/egg_loader] Disable middleware: %s', name);
1468
+ this.options.logger.info(
1469
+ '[@eggjs/core/egg_loader] Disable middleware: %s',
1470
+ name
1471
+ );
1281
1472
  }
1282
1473
  }
1283
1474
 
1284
- this.options.logger.info('[@eggjs/core/egg_loader] Loaded middleware from %j', middlewarePaths);
1475
+ this.options.logger.info(
1476
+ '[@eggjs/core/egg_loader] Loaded middleware from %j',
1477
+ middlewarePaths
1478
+ );
1285
1479
  this.timing.end('Load Middleware');
1286
1480
 
1287
1481
  // add router middleware, make sure router is the last middleware
@@ -1311,15 +1505,21 @@ export class EggLoader {
1311
1505
  // }
1312
1506
  // ```
1313
1507
  if (isGeneratorFunction(obj)) {
1314
- throw new TypeError(`Support for generators was removed, fullpath: ${opt.path}`);
1508
+ throw new TypeError(
1509
+ `Support for generators was removed, fullpath: ${opt.path}`
1510
+ );
1315
1511
  }
1316
- if (!isClass(obj) && !isAsyncFunction(obj)) {
1317
- if (typeof obj === 'function') {
1318
- obj = obj(this.app);
1319
- debug('[loadController] after init(app) => %o, meta: %j', obj, opt);
1320
- if (isGeneratorFunction(obj)) {
1321
- throw new TypeError(`Support for generators was removed, fullpath: ${opt.path}`);
1322
- }
1512
+ if (
1513
+ !isClass(obj) &&
1514
+ !isAsyncFunction(obj) &&
1515
+ typeof obj === 'function'
1516
+ ) {
1517
+ obj = obj(this.app);
1518
+ debug('[loadController] after init(app) => %o, meta: %j', obj, opt);
1519
+ if (isGeneratorFunction(obj)) {
1520
+ throw new TypeError(
1521
+ `Support for generators was removed, fullpath: ${opt.path}`
1522
+ );
1323
1523
  }
1324
1524
  }
1325
1525
  if (isClass(obj)) {
@@ -1331,15 +1531,24 @@ export class EggLoader {
1331
1531
  return wrapObject(obj, opt.path);
1332
1532
  }
1333
1533
  if (isAsyncFunction(obj)) {
1334
- return wrapObject({ 'module.exports': obj }, opt.path)['module.exports'];
1534
+ return wrapObject({ 'module.exports': obj }, opt.path)[
1535
+ 'module.exports'
1536
+ ];
1335
1537
  }
1336
1538
  return obj;
1337
1539
  },
1338
1540
  ...opt,
1339
1541
  };
1340
- await this.loadToApp(controllerBase, 'controller', opt as FileLoaderOptions);
1542
+ await this.loadToApp(
1543
+ controllerBase,
1544
+ 'controller',
1545
+ opt as FileLoaderOptions
1546
+ );
1341
1547
  debug('[loadController] app.controller => %o', this.app.controller);
1342
- this.options.logger.info('[@eggjs/core/egg_loader] Controller loaded: %s', controllerBase);
1548
+ this.options.logger.info(
1549
+ '[@eggjs/core/egg_loader] Controller loaded: %s',
1550
+ controllerBase
1551
+ );
1343
1552
  this.timing.end('Load Controller');
1344
1553
  }
1345
1554
  /** end Controller loader */
@@ -1366,20 +1575,32 @@ export class EggLoader {
1366
1575
  const loaderConfig = {
1367
1576
  ...customLoader[property],
1368
1577
  };
1369
- assert(loaderConfig.directory, `directory is required for config.customLoader.${property}`);
1578
+ assert(
1579
+ loaderConfig.directory,
1580
+ `directory is required for config.customLoader.${property}`
1581
+ );
1370
1582
  let directory: string | string[];
1371
1583
  if (loaderConfig.loadunit === true) {
1372
- directory = this.getLoadUnits().map(unit => path.join(unit.path, loaderConfig.directory));
1584
+ directory = this.getLoadUnits().map(unit =>
1585
+ path.join(unit.path, loaderConfig.directory)
1586
+ );
1373
1587
  } else {
1374
1588
  directory = path.join(this.appInfo.baseDir, loaderConfig.directory);
1375
1589
  }
1376
1590
  const inject = loaderConfig.inject || 'app';
1377
- debug('[loadCustomLoader] loaderConfig: %o, inject: %o, directory: %o',
1378
- loaderConfig, inject, directory);
1591
+ debug(
1592
+ '[loadCustomLoader] loaderConfig: %o, inject: %o, directory: %o',
1593
+ loaderConfig,
1594
+ inject,
1595
+ directory
1596
+ );
1379
1597
 
1380
1598
  switch (inject) {
1381
1599
  case 'ctx': {
1382
- assert(!(property in this.app.context), `customLoader should not override ctx.${property}`);
1600
+ assert(
1601
+ !(property in this.app.context),
1602
+ `customLoader should not override ctx.${property}`
1603
+ );
1383
1604
  const options = {
1384
1605
  caseStyle: CaseStyle.lower,
1385
1606
  fieldClass: `${property}Classes`,
@@ -1390,7 +1611,10 @@ export class EggLoader {
1390
1611
  break;
1391
1612
  }
1392
1613
  case 'app': {
1393
- assert(!(property in this.app), `customLoader should not override app.${property}`);
1614
+ assert(
1615
+ !(property in this.app),
1616
+ `customLoader should not override app.${property}`
1617
+ );
1394
1618
  const options = {
1395
1619
  caseStyle: CaseStyle.lower,
1396
1620
  initializer: (Clazz: unknown) => {
@@ -1416,14 +1640,14 @@ export class EggLoader {
1416
1640
  *
1417
1641
  * @param {String} filepath - fullpath
1418
1642
  * @param {Array} inject - pass rest arguments into the function when invoke
1419
- * @return {Object} exports
1643
+ * @returns {Object} exports
1420
1644
  * @example
1421
1645
  * ```js
1422
1646
  * app.loader.loadFile(path.join(app.options.baseDir, 'config/router.js'));
1423
1647
  * ```
1424
1648
  * @since 1.0.0
1425
1649
  */
1426
- async loadFile(filepath: string, ...inject: any[]) {
1650
+ async loadFile(filepath: string, ...inject: unknown[]) {
1427
1651
  const fullpath = filepath && this.resolveModule(filepath);
1428
1652
  if (!fullpath) {
1429
1653
  return null;
@@ -1431,7 +1655,7 @@ export class EggLoader {
1431
1655
 
1432
1656
  // function(arg1, args, ...) {}
1433
1657
  if (inject.length === 0) {
1434
- inject = [ this.app ];
1658
+ inject = [this.app];
1435
1659
  }
1436
1660
  let mod = await this.requireFile(fullpath);
1437
1661
  if (typeof mod === 'function' && !isClass(mod)) {
@@ -1445,7 +1669,7 @@ export class EggLoader {
1445
1669
 
1446
1670
  /**
1447
1671
  * @param {String} filepath - fullpath
1448
- * @return {Object} exports
1672
+ * @returns {Object} exports
1449
1673
  * @private
1450
1674
  */
1451
1675
  async requireFile(filepath: string) {
@@ -1468,7 +1692,7 @@ export class EggLoader {
1468
1692
  * 2. framework
1469
1693
  * 3. app
1470
1694
  *
1471
- * @return {Array} loadUnits
1695
+ * @returns {Array} loadUnits
1472
1696
  * @since 1.0.0
1473
1697
  */
1474
1698
  getLoadUnits(): EggDirInfo[] {
@@ -1480,7 +1704,7 @@ export class EggLoader {
1480
1704
  if (this.orderPlugins) {
1481
1705
  for (const plugin of this.orderPlugins) {
1482
1706
  this.dirs.push({
1483
- path: plugin.path!,
1707
+ path: plugin.path as string,
1484
1708
  type: 'plugin',
1485
1709
  });
1486
1710
  }
@@ -1511,8 +1735,11 @@ export class EggLoader {
1511
1735
  * @param {Object} options - see {@link FileLoader}
1512
1736
  * @since 1.0.0
1513
1737
  */
1514
- async loadToApp(directory: string | string[], property: string | symbol,
1515
- options?: Omit<FileLoaderOptions, 'inject' | 'target'>) {
1738
+ async loadToApp(
1739
+ directory: string | string[],
1740
+ property: string | symbol,
1741
+ options?: Omit<FileLoaderOptions, 'inject' | 'target'>
1742
+ ) {
1516
1743
  const target = {};
1517
1744
  Reflect.set(this.app, property, target);
1518
1745
  const loadOptions: FileLoaderOptions = {
@@ -1535,8 +1762,11 @@ export class EggLoader {
1535
1762
  * @param {Object} options - see {@link ContextLoader}
1536
1763
  * @since 1.0.0
1537
1764
  */
1538
- async loadToContext(directory: string | string[], property: string | symbol,
1539
- options?: Omit<ContextLoaderOptions, 'inject' | 'property'>) {
1765
+ async loadToContext(
1766
+ directory: string | string[],
1767
+ property: string | symbol,
1768
+ options?: Omit<ContextLoaderOptions, 'inject' | 'property'>
1769
+ ) {
1540
1770
  const loadOptions: ContextLoaderOptions = {
1541
1771
  ...options,
1542
1772
  directory: options?.directory || directory,
@@ -1567,7 +1797,7 @@ export class EggLoader {
1567
1797
  }
1568
1798
 
1569
1799
  getTypeFiles(filename: string) {
1570
- const files = [ `${filename}.default` ];
1800
+ const files = [`${filename}.default`];
1571
1801
  if (this.serverScope) files.push(`${filename}.${this.serverScope}`);
1572
1802
  if (this.serverEnv === 'default') return files;
1573
1803
  files.push(`${filename}.${this.serverEnv}`);
@@ -1581,7 +1811,7 @@ export class EggLoader {
1581
1811
  let fullPath;
1582
1812
  try {
1583
1813
  fullPath = utils.resolvePath(filepath);
1584
- } catch (err: any) {
1814
+ } catch {
1585
1815
  // debug('[resolveModule] Module %o resolve error: %s', filepath, err.stack);
1586
1816
  return undefined;
1587
1817
  }
@@ -1593,7 +1823,10 @@ export class EggLoader {
1593
1823
  }
1594
1824
 
1595
1825
  function depCompatible(plugin: EggPluginInfo & { dep?: string[] }) {
1596
- if (plugin.dep && !(Array.isArray(plugin.dependencies) && plugin.dependencies.length)) {
1826
+ if (
1827
+ plugin.dep &&
1828
+ !(Array.isArray(plugin.dependencies) && plugin.dependencies.length > 0)
1829
+ ) {
1597
1830
  plugin.dependencies = plugin.dep;
1598
1831
  delete plugin.dep;
1599
1832
  }
@@ -1608,8 +1841,10 @@ function isValidatePackageName(name: string) {
1608
1841
  }
1609
1842
 
1610
1843
  // support pathMatching on middleware
1611
- function wrapMiddleware(mw: MiddlewareFunc,
1612
- options: PathMatchingOptions & { enable?: boolean }): MiddlewareFunc | null {
1844
+ function wrapMiddleware(
1845
+ mw: MiddlewareFunc,
1846
+ options: PathMatchingOptions & { enable?: boolean }
1847
+ ): MiddlewareFunc | null {
1613
1848
  // support options.enable
1614
1849
  if (options.enable === false) {
1615
1850
  return null;
@@ -1632,17 +1867,31 @@ function wrapMiddleware(mw: MiddlewareFunc,
1632
1867
  function debugMiddlewareWrapper(mw: MiddlewareFunc): MiddlewareFunc {
1633
1868
  const fn: MiddlewareFunc = async (ctx, next) => {
1634
1869
  const startTime = now();
1635
- debug('[debugMiddlewareWrapper] [%s %s] enter middleware: %s', ctx.method, ctx.url, mw._name);
1870
+ debug(
1871
+ '[debugMiddlewareWrapper] [%s %s] enter middleware: %s',
1872
+ ctx.method,
1873
+ ctx.url,
1874
+ mw._name
1875
+ );
1636
1876
  await mw(ctx, next);
1637
1877
  const rt = diff(startTime);
1638
- debug('[debugMiddlewareWrapper] [%s %s] after middleware: %s [%sms]', ctx.method, ctx.url, mw._name, rt);
1878
+ debug(
1879
+ '[debugMiddlewareWrapper] [%s %s] after middleware: %s [%sms]',
1880
+ ctx.method,
1881
+ ctx.url,
1882
+ mw._name,
1883
+ rt
1884
+ );
1639
1885
  };
1640
1886
  fn._name = `${mw._name}DebugWrapper`;
1641
1887
  return fn;
1642
1888
  }
1643
1889
 
1644
1890
  // wrap the controller class, yield a object with middlewares
1645
- function wrapControllerClass(Controller: typeof BaseContextClass, fullPath: string) {
1891
+ function wrapControllerClass(
1892
+ Controller: typeof BaseContextClass,
1893
+ fullPath: string
1894
+ ) {
1646
1895
  let proto = Controller.prototype;
1647
1896
  const ret: Record<string, any> = {};
1648
1897
  // tracing the prototype chain
@@ -1657,11 +1906,12 @@ function wrapControllerClass(Controller: typeof BaseContextClass, fullPath: stri
1657
1906
  // skip getter, setter & non-function properties
1658
1907
  const d = Object.getOwnPropertyDescriptor(proto, key);
1659
1908
  // prevent to override sub method
1660
- if (typeof d?.value === 'function' && !ret.hasOwnProperty(key)) {
1909
+ if (typeof d?.value === 'function' && !Object.hasOwn(ret, key)) {
1661
1910
  const controllerMethodName = `${Controller.name}.${key}`;
1662
1911
  if (isGeneratorFunction(d.value)) {
1663
1912
  throw new TypeError(
1664
- `Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`);
1913
+ `Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`
1914
+ );
1665
1915
  }
1666
1916
  ret[key] = controllerMethodToMiddleware(Controller, key);
1667
1917
  ret[key][FULLPATH] = `${fullPath}#${controllerMethodName}()`;
@@ -1672,18 +1922,26 @@ function wrapControllerClass(Controller: typeof BaseContextClass, fullPath: stri
1672
1922
  return ret;
1673
1923
  }
1674
1924
 
1675
- function controllerMethodToMiddleware(Controller: typeof BaseContextClass, key: string) {
1676
- return function classControllerMiddleware(this: Context, ...args: any[]) {
1677
- const controller: any = new Controller(this);
1925
+ function controllerMethodToMiddleware(
1926
+ Controller: typeof BaseContextClass,
1927
+ key: string
1928
+ ) {
1929
+ return function classControllerMiddleware(this: Context, ...args: unknown[]) {
1930
+ const controller = new Controller(this);
1678
1931
  if (!this.app.config.controller?.supportParams) {
1679
- args = [ this ];
1932
+ args = [this];
1680
1933
  }
1934
+ // @ts-expect-error key exists
1681
1935
  return controller[key](...args);
1682
1936
  };
1683
1937
  }
1684
1938
 
1685
1939
  // wrap the method of the object, method can receive ctx as it's first argument
1686
- function wrapObject(obj: Record<string, any>, fullPath: string, prefix?: string) {
1940
+ function wrapObject(
1941
+ obj: Record<string, any>,
1942
+ fullPath: string,
1943
+ prefix?: string
1944
+ ) {
1687
1945
  const keys = Object.keys(obj);
1688
1946
  const ret: Record<string, any> = {};
1689
1947
  prefix = prefix ?? '';
@@ -1691,12 +1949,16 @@ function wrapObject(obj: Record<string, any>, fullPath: string, prefix?: string)
1691
1949
  const controllerMethodName = `${prefix}${key}`;
1692
1950
  const item = obj[key];
1693
1951
  if (isGeneratorFunction(item)) {
1694
- throw new TypeError(`Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`);
1952
+ throw new TypeError(
1953
+ `Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`
1954
+ );
1695
1955
  }
1696
1956
  if (typeof item === 'function') {
1697
1957
  const names = getParamNames(item);
1698
1958
  if (names[0] === 'next') {
1699
- throw new Error(`controller \`${controllerMethodName}\` should not use next as argument from file ${fullPath}`);
1959
+ throw new Error(
1960
+ `controller \`${controllerMethodName}\` should not use next as argument from file ${fullPath}`
1961
+ );
1700
1962
  }
1701
1963
  ret[key] = objectFunctionToMiddleware(item);
1702
1964
  ret[key][FULLPATH] = `${fullPath}#${controllerMethodName}()`;
@@ -1709,9 +1971,9 @@ function wrapObject(obj: Record<string, any>, fullPath: string, prefix?: string)
1709
1971
  }
1710
1972
 
1711
1973
  function objectFunctionToMiddleware(func: Fun) {
1712
- async function objectControllerMiddleware(this: Context, ...args: any[]) {
1974
+ async function objectControllerMiddleware(this: Context, ...args: unknown[]) {
1713
1975
  if (!this.app.config.controller?.supportParams) {
1714
- args = [ this ];
1976
+ args = [this];
1715
1977
  }
1716
1978
  return await func.apply(this, args);
1717
1979
  }