@eggjs/core 6.4.1 → 6.6.0-beta.2

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 (87) hide show
  1. package/README.md +23 -27
  2. package/dist/base_context_class.d.ts +21 -0
  3. package/dist/base_context_class.js +40 -0
  4. package/dist/egg.d.ts +248 -0
  5. package/dist/egg.js +358 -0
  6. package/dist/index.d.ts +12 -0
  7. package/dist/index.js +12 -0
  8. package/dist/lifecycle.d.ts +84 -0
  9. package/dist/lifecycle.js +280 -0
  10. package/dist/loader/context_loader.d.ts +39 -0
  11. package/dist/loader/context_loader.js +79 -0
  12. package/dist/loader/egg_loader.d.ts +374 -0
  13. package/dist/loader/egg_loader.js +1184 -0
  14. package/dist/loader/file_loader.d.ts +105 -0
  15. package/dist/loader/file_loader.js +198 -0
  16. package/dist/singleton.d.ts +33 -0
  17. package/dist/singleton.js +107 -0
  18. package/{src/types.ts → dist/types.d.ts} +7 -7
  19. package/dist/utils/index.d.ts +19 -0
  20. package/dist/utils/index.js +103 -0
  21. package/dist/utils/sequencify.d.ts +16 -0
  22. package/dist/utils/sequencify.js +46 -0
  23. package/dist/utils/timing.d.ts +24 -0
  24. package/dist/utils/timing.js +85 -0
  25. package/package.json +35 -63
  26. package/dist/commonjs/base_context_class.d.ts +0 -16
  27. package/dist/commonjs/base_context_class.js +0 -41
  28. package/dist/commonjs/egg.d.ts +0 -247
  29. package/dist/commonjs/egg.js +0 -401
  30. package/dist/commonjs/index.d.ts +0 -12
  31. package/dist/commonjs/index.js +0 -32
  32. package/dist/commonjs/lifecycle.d.ts +0 -78
  33. package/dist/commonjs/lifecycle.js +0 -312
  34. package/dist/commonjs/loader/context_loader.d.ts +0 -35
  35. package/dist/commonjs/loader/context_loader.js +0 -110
  36. package/dist/commonjs/loader/egg_loader.d.ts +0 -369
  37. package/dist/commonjs/loader/egg_loader.js +0 -1543
  38. package/dist/commonjs/loader/file_loader.d.ts +0 -100
  39. package/dist/commonjs/loader/file_loader.js +0 -262
  40. package/dist/commonjs/package.json +0 -3
  41. package/dist/commonjs/singleton.d.ts +0 -29
  42. package/dist/commonjs/singleton.js +0 -125
  43. package/dist/commonjs/types.d.ts +0 -53
  44. package/dist/commonjs/types.js +0 -3
  45. package/dist/commonjs/utils/index.d.ts +0 -17
  46. package/dist/commonjs/utils/index.js +0 -117
  47. package/dist/commonjs/utils/sequencify.d.ts +0 -13
  48. package/dist/commonjs/utils/sequencify.js +0 -59
  49. package/dist/commonjs/utils/timing.d.ts +0 -21
  50. package/dist/commonjs/utils/timing.js +0 -100
  51. package/dist/esm/base_context_class.d.ts +0 -16
  52. package/dist/esm/base_context_class.js +0 -37
  53. package/dist/esm/egg.d.ts +0 -247
  54. package/dist/esm/egg.js +0 -388
  55. package/dist/esm/index.d.ts +0 -12
  56. package/dist/esm/index.js +0 -12
  57. package/dist/esm/lifecycle.d.ts +0 -78
  58. package/dist/esm/lifecycle.js +0 -305
  59. package/dist/esm/loader/context_loader.d.ts +0 -35
  60. package/dist/esm/loader/context_loader.js +0 -102
  61. package/dist/esm/loader/egg_loader.d.ts +0 -369
  62. package/dist/esm/loader/egg_loader.js +0 -1536
  63. package/dist/esm/loader/file_loader.d.ts +0 -100
  64. package/dist/esm/loader/file_loader.js +0 -255
  65. package/dist/esm/package.json +0 -3
  66. package/dist/esm/singleton.d.ts +0 -29
  67. package/dist/esm/singleton.js +0 -118
  68. package/dist/esm/types.d.ts +0 -53
  69. package/dist/esm/types.js +0 -2
  70. package/dist/esm/utils/index.d.ts +0 -17
  71. package/dist/esm/utils/index.js +0 -112
  72. package/dist/esm/utils/sequencify.d.ts +0 -13
  73. package/dist/esm/utils/sequencify.js +0 -56
  74. package/dist/esm/utils/timing.d.ts +0 -21
  75. package/dist/esm/utils/timing.js +0 -93
  76. package/dist/package.json +0 -4
  77. package/src/base_context_class.ts +0 -39
  78. package/src/egg.ts +0 -517
  79. package/src/index.ts +0 -14
  80. package/src/lifecycle.ts +0 -399
  81. package/src/loader/context_loader.ts +0 -121
  82. package/src/loader/egg_loader.ts +0 -1722
  83. package/src/loader/file_loader.ts +0 -308
  84. package/src/singleton.ts +0 -149
  85. package/src/utils/index.ts +0 -125
  86. package/src/utils/sequencify.ts +0 -70
  87. package/src/utils/timing.ts +0 -114
@@ -1,308 +0,0 @@
1
- import assert from 'node:assert';
2
- import fs from 'node:fs';
3
- import { debuglog } from 'node:util';
4
- import path from 'node:path';
5
- import globby from 'globby';
6
- import { isClass, isGeneratorFunction, isAsyncFunction, isPrimitive } from 'is-type-of';
7
- import { isSupportTypeScript } from '@eggjs/utils';
8
- import utils, { Fun } from '../utils/index.js';
9
-
10
- const debug = debuglog('@eggjs/core/file_loader');
11
-
12
- export const FULLPATH = Symbol('EGG_LOADER_ITEM_FULLPATH');
13
- export const EXPORTS = Symbol('EGG_LOADER_ITEM_EXPORTS');
14
-
15
- export enum CaseStyle {
16
- camel = 'camel',
17
- lower = 'lower',
18
- upper = 'upper',
19
- }
20
-
21
- export type CaseStyleFunction = (filepath: string) => string[];
22
- export type FileLoaderInitializer = (exports: unknown, options: { path: string; pathName: string }) => unknown;
23
- export type FileLoaderFilter = (exports: unknown) => boolean;
24
-
25
- export interface FileLoaderOptions {
26
- /** directories to be loaded */
27
- directory: string | string[];
28
- /** attach the target object from loaded files */
29
- target: Record<string, any>;
30
- /** match the files when load, support glob, default to all js files */
31
- match?: string | string[];
32
- /** ignore the files when load, support glob */
33
- ignore?: string | string[];
34
- /** custom file exports, receive two parameters, first is the inject object(if not js file, will be content buffer), second is an `options` object that contain `path` */
35
- initializer?: FileLoaderInitializer;
36
- /** determine whether invoke when exports is function */
37
- call?: boolean;
38
- /** determine whether override the property when get the same name */
39
- override?: boolean;
40
- /** an object that be the argument when invoke the function */
41
- inject?: Record<string, any>;
42
- /** a function that filter the exports which can be loaded */
43
- filter?: FileLoaderFilter;
44
- /** set property's case when converting a filepath to property list. */
45
- caseStyle?: CaseStyle | CaseStyleFunction;
46
- lowercaseFirst?: boolean;
47
- }
48
-
49
- export interface FileLoaderParseItem {
50
- fullpath: string;
51
- properties: string[];
52
- exports: object | Fun;
53
- }
54
-
55
- /**
56
- * Load files from directory to target object.
57
- * @since 1.0.0
58
- */
59
- export class FileLoader {
60
- static get FULLPATH() {
61
- return FULLPATH;
62
- }
63
-
64
- static get EXPORTS() {
65
- return EXPORTS;
66
- }
67
-
68
- readonly options: FileLoaderOptions & Required<Pick<FileLoaderOptions, 'caseStyle'>>;
69
-
70
- /**
71
- * @class
72
- * @param {Object} options - options
73
- * @param {String|Array} options.directory - directories to be loaded
74
- * @param {Object} options.target - attach the target object from loaded files
75
- * @param {String} options.match - match the files when load, support glob, default to all js files
76
- * @param {String} options.ignore - ignore the files when load, support glob
77
- * @param {Function} options.initializer - custom file exports, receive two parameters, first is the inject object(if not js file, will be content buffer), second is an `options` object that contain `path`
78
- * @param {Boolean} options.call - determine whether invoke when exports is function
79
- * @param {Boolean} options.override - determine whether override the property when get the same name
80
- * @param {Object} options.inject - an object that be the argument when invoke the function
81
- * @param {Function} options.filter - a function that filter the exports which can be loaded
82
- * @param {String|Function} options.caseStyle - set property's case when converting a filepath to property list.
83
- */
84
- constructor(options: FileLoaderOptions) {
85
- assert(options.directory, 'options.directory is required');
86
- assert(options.target, 'options.target is required');
87
- this.options = {
88
- caseStyle: CaseStyle.camel,
89
- call: true,
90
- override: false,
91
- ...options,
92
- };
93
-
94
- // compatible old options _lowercaseFirst_
95
- if (this.options.lowercaseFirst === true) {
96
- utils.deprecated('lowercaseFirst is deprecated, use caseStyle instead');
97
- this.options.caseStyle = CaseStyle.lower;
98
- }
99
- }
100
-
101
- /**
102
- * attach items to target object. Mapping the directory to properties.
103
- * `app/controller/group/repository.js` => `target.group.repository`
104
- * @return {Object} target
105
- * @since 1.0.0
106
- */
107
- async load(): Promise<object> {
108
- const items = await this.parse();
109
- const target = this.options.target;
110
- for (const item of items) {
111
- debug('loading item: %o', item);
112
- // item { properties: [ 'a', 'b', 'c'], exports }
113
- // => target.a.b.c = exports
114
- item.properties.reduce((target, property, index) => {
115
- let obj;
116
- const properties = item.properties.slice(0, index + 1).join('.');
117
- if (index === item.properties.length - 1) {
118
- if (property in target) {
119
- if (!this.options.override) throw new Error(`can't overwrite property '${properties}' from ${target[property][FULLPATH]} by ${item.fullpath}`);
120
- }
121
- obj = item.exports;
122
- if (obj && !isPrimitive(obj)) {
123
- Reflect.set(obj, FULLPATH, item.fullpath);
124
- Reflect.set(obj, EXPORTS, true);
125
- }
126
- } else {
127
- obj = target[property] || {};
128
- }
129
- target[property] = obj;
130
- debug('loaded item properties: %o => %o', properties, obj);
131
- return obj;
132
- }, target);
133
- }
134
- return target;
135
- }
136
-
137
- /**
138
- * Parse files from given directories, then return an items list, each item contains properties and exports.
139
- *
140
- * For example, parse `app/controller/group/repository.js`
141
- *
142
- * ```
143
- * module.exports = app => {
144
- * return class RepositoryController extends app.Controller {};
145
- * }
146
- * ```
147
- *
148
- * It returns a item
149
- *
150
- * ```
151
- * {
152
- * properties: [ 'group', 'repository' ],
153
- * exports: app => { ... },
154
- * }
155
- * ```
156
- *
157
- * `Properties` is an array that contains the directory of a filepath.
158
- *
159
- * `Exports` depends on type, if exports is a function, it will be called. if initializer is specified, it will be called with exports for customizing.
160
- * @return {Array} items
161
- * @since 1.0.0
162
- */
163
- protected async parse(): Promise<FileLoaderParseItem[]> {
164
- let files = this.options.match;
165
- if (!files) {
166
- files = isSupportTypeScript()
167
- ? [ '**/*.(js|ts)', '!**/*.d.ts' ]
168
- : [ '**/*.js' ];
169
- } else {
170
- files = Array.isArray(files) ? files : [ files ];
171
- }
172
-
173
- let ignore = this.options.ignore;
174
- if (ignore) {
175
- ignore = Array.isArray(ignore) ? ignore : [ ignore ];
176
- ignore = ignore.filter(f => !!f).map(f => '!' + f);
177
- files = files.concat(ignore);
178
- }
179
-
180
- let directories = this.options.directory;
181
- if (!Array.isArray(directories)) {
182
- directories = [ directories ];
183
- }
184
-
185
- const filter = typeof this.options.filter === 'function' ? this.options.filter : null;
186
- const items: FileLoaderParseItem[] = [];
187
- debug('[parse] parsing directories: %j', directories);
188
- for (const directory of directories) {
189
- const filepaths = globby.sync(files, { cwd: directory });
190
- debug('[parse] globby files: %o, cwd: %o => %o', files, directory, filepaths);
191
- for (const filepath of filepaths) {
192
- const fullpath = path.join(directory, filepath);
193
- if (!fs.statSync(fullpath).isFile()) continue;
194
- if (filepath.endsWith('.js')) {
195
- const filepathTs = filepath.replace(/\.js$/, '.ts');
196
- if (filepaths.includes(filepathTs)) {
197
- debug('[parse] ignore %s, because %s exists', fullpath, filepathTs);
198
- continue;
199
- }
200
- }
201
- // get properties
202
- // app/service/foo/bar.js => [ 'foo', 'bar' ]
203
- const properties = getProperties(filepath, this.options.caseStyle);
204
- // app/service/foo/bar.js => service.foo.bar
205
- const pathName = directory.split(/[/\\]/).slice(-1) + '.' + properties.join('.');
206
- // get exports from the file
207
- const exports = await getExports(fullpath, this.options, pathName);
208
-
209
- // ignore exports when it's null or false returned by filter function
210
- if (exports == null || (filter && filter(exports) === false)) {
211
- continue;
212
- }
213
-
214
- // set properties of class
215
- if (isClass(exports)) {
216
- exports.prototype.pathName = pathName;
217
- exports.prototype.fullPath = fullpath;
218
- }
219
-
220
- items.push({ fullpath, properties, exports });
221
- debug('[parse] parse %s, properties %j, exports %o', fullpath, properties, exports);
222
- }
223
- }
224
-
225
- return items;
226
- }
227
- }
228
-
229
- // convert file path to an array of properties
230
- // a/b/c.js => ['a', 'b', 'c']
231
- function getProperties(filepath: string, caseStyle: CaseStyle | CaseStyleFunction) {
232
- // if caseStyle is function, return the result of function
233
- if (typeof caseStyle === 'function') {
234
- const result = caseStyle(filepath);
235
- assert(Array.isArray(result), `caseStyle expect an array, but got ${JSON.stringify(result)}`);
236
- return result;
237
- }
238
- // use default camelize
239
- return defaultCamelize(filepath, caseStyle);
240
- }
241
-
242
- // Get exports from filepath
243
- // If exports is null/undefined, it will be ignored
244
- async function getExports(fullpath: string, options: FileLoaderOptions, pathName: string) {
245
- let exports = await utils.loadFile(fullpath);
246
- // process exports as you like
247
- if (options.initializer) {
248
- exports = options.initializer(exports, { path: fullpath, pathName });
249
- debug('[getExports] after initializer => %o', exports);
250
- }
251
-
252
- if (isGeneratorFunction(exports)) {
253
- throw new TypeError(`Support for generators was removed, fullpath: ${fullpath}`);
254
- }
255
-
256
- // return exports when it's a class or async function
257
- //
258
- // module.exports = class Service {};
259
- // or
260
- // module.exports = async function() {}
261
- if (isClass(exports) || isAsyncFunction(exports)) {
262
- return exports;
263
- }
264
-
265
- // return exports after call when it's a function
266
- //
267
- // module.exports = function(app) {
268
- // return {};
269
- // }
270
- if (options.call && typeof exports === 'function') {
271
- exports = exports(options.inject);
272
- if (exports != null) {
273
- return exports;
274
- }
275
- }
276
-
277
- // return exports what is
278
- return exports;
279
- }
280
-
281
- function defaultCamelize(filepath: string, caseStyle: CaseStyle) {
282
- const properties = filepath.substring(0, filepath.lastIndexOf('.')).split('/');
283
- return properties.map(property => {
284
- if (!/^[a-z][a-z0-9_-]*$/i.test(property)) {
285
- throw new Error(`${property} is not match 'a-z0-9_-' in ${filepath}`);
286
- }
287
-
288
- // use default camelize, will capitalize the first letter
289
- // foo_bar.js > FooBar
290
- // fooBar.js > FooBar
291
- // FooBar.js > FooBar
292
- // FooBar.js > FooBar
293
- // FooBar.js > fooBar (if lowercaseFirst is true)
294
- property = property.replace(/[_-][a-z]/ig, s => s.substring(1).toUpperCase());
295
- let first = property[0];
296
- switch (caseStyle) {
297
- case 'lower':
298
- first = first.toLowerCase();
299
- break;
300
- case 'upper':
301
- first = first.toUpperCase();
302
- break;
303
- case 'camel':
304
- default:
305
- }
306
- return first + property.substring(1);
307
- });
308
- }
package/src/singleton.ts DELETED
@@ -1,149 +0,0 @@
1
- import assert from 'node:assert';
2
- import { isAsyncFunction } from 'is-type-of';
3
- import type { EggCore } from './egg.js';
4
-
5
- export type SingletonCreateMethod =
6
- (config: Record<string, any>, app: EggCore, clientName: string) => unknown | Promise<unknown>;
7
-
8
- export interface SingletonOptions {
9
- name: string;
10
- app: EggCore;
11
- create: SingletonCreateMethod;
12
- }
13
-
14
- export class Singleton<T = any> {
15
- readonly clients = new Map<string, T>();
16
- readonly app: EggCore;
17
- readonly create: SingletonCreateMethod;
18
- readonly name: string;
19
- readonly options: Record<string, any>;
20
-
21
- constructor(options: SingletonOptions) {
22
- assert(options.name, '[@eggjs/core/singleton] Singleton#constructor options.name is required');
23
- assert(options.app, '[@eggjs/core/singleton] Singleton#constructor options.app is required');
24
- assert(options.create, '[@eggjs/core/singleton] Singleton#constructor options.create is required');
25
- assert(!(options.name in options.app), `[@eggjs/core/singleton] ${options.name} is already exists in app`);
26
- this.app = options.app;
27
- this.name = options.name;
28
- this.create = options.create;
29
- this.options = options.app.config[this.name] ?? {};
30
- }
31
-
32
- init() {
33
- return isAsyncFunction(this.create) ? this.initAsync() : this.initSync();
34
- }
35
-
36
- initSync() {
37
- const options = this.options;
38
- assert(!(options.client && options.clients),
39
- `[@eggjs/core/singleton] ${this.name} can not set options.client and options.clients both`);
40
-
41
- // alias app[name] as client, but still support createInstance method
42
- if (options.client) {
43
- const client = this.createInstance(options.client, options.name);
44
- this.#setClientToApp(client);
45
- this.#extendDynamicMethods(client);
46
- return;
47
- }
48
-
49
- // multi client, use app[name].getSingletonInstance(id)
50
- if (options.clients) {
51
- Object.keys(options.clients).forEach(id => {
52
- const client = this.createInstance(options.clients[id], id);
53
- this.clients.set(id, client);
54
- });
55
- this.#setClientToApp(this);
56
- return;
57
- }
58
-
59
- // no config.clients and config.client
60
- this.#setClientToApp(this);
61
- }
62
-
63
- async initAsync() {
64
- const options = this.options;
65
- assert(!(options.client && options.clients),
66
- `[@eggjs/core/singleton] ${this.name} can not set options.client and options.clients both`);
67
-
68
- // alias app[name] as client, but still support createInstance method
69
- if (options.client) {
70
- const client = await this.createInstanceAsync(options.client, options.name);
71
- this.#setClientToApp(client);
72
- this.#extendDynamicMethods(client);
73
- return;
74
- }
75
-
76
- // multi client, use app[name].getInstance(id)
77
- if (options.clients) {
78
- await Promise.all(Object.keys(options.clients).map((id: string) => {
79
- return this.createInstanceAsync(options.clients[id], id)
80
- .then(client => this.clients.set(id, client));
81
- }));
82
- this.#setClientToApp(this);
83
- return;
84
- }
85
-
86
- // no config.clients and config.client
87
- this.#setClientToApp(this);
88
- }
89
-
90
- #setClientToApp(client: unknown) {
91
- Reflect.set(this.app, this.name, client);
92
- }
93
-
94
- /**
95
- * @deprecated please use `getSingletonInstance(id)` instead
96
- */
97
- get(id: string) {
98
- return this.clients.get(id)!;
99
- }
100
-
101
- /**
102
- * Get singleton instance by id
103
- */
104
- getSingletonInstance(id: string) {
105
- return this.clients.get(id)!;
106
- }
107
-
108
- createInstance(config: Record<string, any>, clientName: string) {
109
- // async creator only support createInstanceAsync
110
- assert(!isAsyncFunction(this.create),
111
- `[@eggjs/core/singleton] ${this.name} only support asynchronous creation, please use createInstanceAsync`);
112
- // options.default will be merge in to options.clients[id]
113
- config = {
114
- ...this.options.default,
115
- ...config,
116
- };
117
- return (this.create as SingletonCreateMethod)(config, this.app, clientName) as T;
118
- }
119
-
120
- async createInstanceAsync(config: Record<string, any>, clientName: string) {
121
- // options.default will be merge in to options.clients[id]
122
- config = {
123
- ...this.options.default,
124
- ...config,
125
- };
126
- return await this.create(config, this.app, clientName) as T;
127
- }
128
-
129
- #extendDynamicMethods(client: any) {
130
- assert(!client.createInstance, '[@eggjs/core/singleton] singleton instance should not have createInstance method');
131
- assert(!client.createInstanceAsync, '[@eggjs/core/singleton] singleton instance should not have createInstanceAsync method');
132
-
133
- try {
134
- let extendable = client;
135
- // Object.preventExtensions() or Object.freeze()
136
- if (!Object.isExtensible(client) || Object.isFrozen(client)) {
137
- // eslint-disable-next-line no-proto
138
- extendable = client.__proto__ || client;
139
- }
140
- extendable.createInstance = this.createInstance.bind(this);
141
- extendable.createInstanceAsync = this.createInstanceAsync.bind(this);
142
- } catch (err) {
143
- this.app.coreLogger.warn(
144
- '[@eggjs/core/singleton] %s dynamic create is disabled because of client is un-extendable',
145
- this.name);
146
- this.app.coreLogger.warn(err);
147
- }
148
- }
149
- }
@@ -1,125 +0,0 @@
1
- import { debuglog } from 'node:util';
2
- import path from 'node:path';
3
- import fs from 'node:fs';
4
- import { stat } from 'node:fs/promises';
5
- import BuiltinModule from 'node:module';
6
- import { importResolve, importModule } from '@eggjs/utils';
7
-
8
- const debug = debuglog('@eggjs/core/utils');
9
-
10
- export type Fun = (...args: any[]) => any;
11
-
12
- // Guard against poorly mocked module constructors.
13
- const Module = typeof module !== 'undefined' && module.constructor.length > 1
14
- ? module.constructor
15
- /* istanbul ignore next */
16
- : BuiltinModule;
17
-
18
- const extensions = (Module as any)._extensions;
19
- const extensionNames = Object.keys(extensions).concat([ '.cjs', '.mjs' ]);
20
- debug('Module extensions: %j', extensionNames);
21
-
22
- function getCalleeFromStack(withLine?: boolean, stackIndex?: number) {
23
- stackIndex = stackIndex === undefined ? 2 : stackIndex;
24
- const limit = Error.stackTraceLimit;
25
- const prep = Error.prepareStackTrace;
26
-
27
- Error.prepareStackTrace = prepareObjectStackTrace;
28
- Error.stackTraceLimit = 5;
29
-
30
- // capture the stack
31
- const obj: any = {};
32
- Error.captureStackTrace(obj);
33
- let callSite = obj.stack[stackIndex];
34
- let fileName = '';
35
- if (callSite) {
36
- // egg-mock will create a proxy
37
- // https://github.com/eggjs/egg-mock/blob/master/lib/app.js#L174
38
- fileName = callSite.getFileName();
39
- /* istanbul ignore if */
40
- if (fileName && fileName.endsWith('egg-mock/lib/app.js')) {
41
- // TODO: add test
42
- callSite = obj.stack[stackIndex + 1];
43
- fileName = callSite.getFileName();
44
- }
45
- }
46
-
47
- Error.prepareStackTrace = prep;
48
- Error.stackTraceLimit = limit;
49
-
50
- if (!callSite || !fileName) return '<anonymous>';
51
- if (!withLine) return fileName;
52
- return `${fileName}:${callSite.getLineNumber()}:${callSite.getColumnNumber()}`;
53
- }
54
-
55
- export default {
56
- deprecated(message: string) {
57
- if (debug.enabled) {
58
- console.trace('[@eggjs/core/deprecated] %s', message);
59
- } else {
60
- console.log('[@eggjs/core/deprecated] %s', message);
61
- console.log('[@eggjs/core/deprecated] set NODE_DEBUG=@eggjs/core/utils can show call stack');
62
- }
63
- },
64
-
65
- extensions,
66
- extensionNames,
67
-
68
- async existsPath(filepath: string) {
69
- try {
70
- await stat(filepath);
71
- return true;
72
- } catch {
73
- return false;
74
- }
75
- },
76
-
77
- async loadFile(filepath: string) {
78
- try {
79
- // if not js module, just return content buffer
80
- const extname = path.extname(filepath);
81
- if (extname && !extensionNames.includes(extname) && extname !== '.ts') {
82
- return fs.readFileSync(filepath);
83
- }
84
- const obj = await importModule(filepath, { importDefaultOnly: true });
85
- return obj;
86
- } catch (e: any) {
87
- if (!e.message && typeof e !== 'string') {
88
- // ts error: test/fixtures/apps/app-ts/app/extend/context.ts(5,17): error TS2339: Property 'url' does not exist on type 'Context'
89
- console.trace(e);
90
- throw e;
91
- }
92
- const err = new Error(`[@eggjs/core] load file: ${filepath}, error: ${e.message}`);
93
- err.cause = e;
94
- debug('[loadFile] handle %s error: %s', filepath, e);
95
- throw err;
96
- }
97
- },
98
-
99
- resolvePath(filepath: string, options?: { paths?: string[] }) {
100
- return importResolve(filepath, options);
101
- },
102
-
103
- methods: [ 'head', 'options', 'get', 'put', 'patch', 'post', 'delete' ],
104
-
105
- async callFn(fn: Fun, args?: any[], ctx?: any) {
106
- args = args || [];
107
- if (typeof fn !== 'function') return;
108
- return ctx ? fn.call(ctx, ...args) : fn(...args);
109
- },
110
-
111
- getCalleeFromStack,
112
-
113
- getResolvedFilename(filepath: string, baseDir: string) {
114
- const reg = /[/\\]/g;
115
- return filepath.replace(baseDir + path.sep, '').replace(reg, '/');
116
- },
117
- };
118
-
119
- /**
120
- * Capture call site stack from v8.
121
- * https://github.com/v8/v8/wiki/Stack-Trace-API
122
- */
123
- function prepareObjectStackTrace(_obj: any, stack: any) {
124
- return stack;
125
- }
@@ -1,70 +0,0 @@
1
- import { debuglog } from 'node:util';
2
-
3
- const debug = debuglog('@eggjs/core/utils/sequencify');
4
-
5
- export interface SequencifyResult {
6
- sequence: string[];
7
- requires: Record<string, true>;
8
- }
9
-
10
- export interface SequencifyTask {
11
- dependencies: string[];
12
- optionalDependencies: string[];
13
- }
14
-
15
- function sequence(tasks: Record<string, SequencifyTask>, names: string[], result: SequencifyResult,
16
- missing: string[], recursive: string[],
17
- nest: string[], optional: boolean, parent: string) {
18
- names.forEach(function(name) {
19
- if (result.requires[name]) return;
20
-
21
- const node = tasks[name];
22
- if (!node) {
23
- if (optional === true) return;
24
- missing.push(name);
25
- } else if (nest.includes(name)) {
26
- nest.push(name);
27
- recursive.push(...nest.slice(0));
28
- nest.pop();
29
- } else if (node.dependencies.length || node.optionalDependencies.length) {
30
- nest.push(name);
31
- if (node.dependencies.length) {
32
- sequence(tasks, node.dependencies, result, missing, recursive, nest, optional, name);
33
- }
34
- if (node.optionalDependencies.length) {
35
- sequence(tasks, node.optionalDependencies, result, missing, recursive, nest, true, name);
36
- }
37
- nest.pop();
38
- }
39
- if (!optional) {
40
- result.requires[name] = true;
41
- debug('task: %s is enabled by %s', name, parent);
42
- }
43
- if (!result.sequence.includes(name)) {
44
- result.sequence.push(name);
45
- }
46
- });
47
- }
48
-
49
- // tasks: object with keys as task names
50
- // names: array of task names
51
- export default function sequencify(tasks: Record<string, SequencifyTask>, names: string[]) {
52
- const result: SequencifyResult = {
53
- sequence: [],
54
- requires: {},
55
- }; // the final sequence
56
- const missing: string[] = []; // missing tasks
57
- const recursive: string[] = []; // recursive task dependencies
58
-
59
- sequence(tasks, names, result, missing, recursive, [], false, 'app');
60
-
61
- if (missing.length || recursive.length) {
62
- result.sequence = []; // results are incomplete at best, completely wrong at worst, remove them to avoid confusion
63
- }
64
-
65
- return {
66
- sequence: result.sequence.filter(item => result.requires[item]),
67
- missingTasks: missing,
68
- recursiveDependencies: recursive,
69
- };
70
- }