@eggjs/utils 3.0.1 → 4.0.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.
@@ -0,0 +1,72 @@
1
+ import { debuglog } from 'node:util';
2
+ import { createRequire } from 'node:module';
3
+ import { pathToFileURL } from 'node:url';
4
+ const debug = debuglog('@eggjs/utils:loader');
5
+ let _customRequire;
6
+ export function importResolve(filepath, options) {
7
+ if (!_customRequire) {
8
+ if (typeof require !== 'undefined') {
9
+ _customRequire = require;
10
+ }
11
+ else {
12
+ _customRequire = createRequire(process.cwd());
13
+ }
14
+ }
15
+ const moduleFilePath = _customRequire.resolve(filepath, options);
16
+ debug('[importResolve] %o, options: %o => %o', filepath, options, moduleFilePath);
17
+ return moduleFilePath;
18
+ }
19
+ export async function importModule(filepath, options) {
20
+ const moduleFilePath = importResolve(filepath, options);
21
+ let obj;
22
+ if (typeof require === 'function') {
23
+ // commonjs
24
+ obj = require(moduleFilePath);
25
+ debug('[importModule] require %o => %o', filepath, obj);
26
+ if (obj?.__esModule === true && 'default' in obj) {
27
+ // 兼容 cjs 模拟 esm 的导出格式
28
+ // {
29
+ // __esModule: true,
30
+ // default: { fn: [Function: fn], foo: 'bar', one: 1 }
31
+ // }
32
+ obj = obj.default;
33
+ }
34
+ }
35
+ else {
36
+ // esm
37
+ debug('[importModule] await import start: %o', filepath);
38
+ const fileUrl = pathToFileURL(moduleFilePath).toString();
39
+ obj = await import(fileUrl);
40
+ debug('[importModule] await import end: %o => %o', filepath, obj);
41
+ // {
42
+ // default: { foo: 'bar', one: 1 },
43
+ // foo: 'bar',
44
+ // one: 1,
45
+ // [Symbol(Symbol.toStringTag)]: 'Module'
46
+ // }
47
+ if (obj?.__esModule === true && obj?.default?.__esModule === true) {
48
+ // 兼容 cjs 模拟 esm 的导出格式
49
+ // {
50
+ // __esModule: true,
51
+ // default: {
52
+ // __esModule: true,
53
+ // default: {
54
+ // fn: [Function: fn] { [length]: 0, [name]: 'fn' },
55
+ // foo: 'bar',
56
+ // one: 1
57
+ // }
58
+ // },
59
+ // [Symbol(Symbol.toStringTag)]: 'Module'
60
+ // }
61
+ obj = obj.default;
62
+ }
63
+ if (options?.importDefaultOnly) {
64
+ if ('default' in obj) {
65
+ obj = obj.default;
66
+ }
67
+ }
68
+ }
69
+ debug('[importModule] return %o => %o', filepath, obj);
70
+ return obj;
71
+ }
72
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1wb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ltcG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDNUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUV6QyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUU5QyxJQUFJLGNBQTJCLENBQUM7QUFXaEMsTUFBTSxVQUFVLGFBQWEsQ0FBQyxRQUFnQixFQUFFLE9BQThCO0lBQzVFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNwQixJQUFJLE9BQU8sT0FBTyxLQUFLLFdBQVcsRUFBRSxDQUFDO1lBQ25DLGNBQWMsR0FBRyxPQUFPLENBQUM7UUFDM0IsQ0FBQzthQUFNLENBQUM7WUFDTixjQUFjLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ2hELENBQUM7SUFDSCxDQUFDO0lBQ0QsTUFBTSxjQUFjLEdBQUcsY0FBYyxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDakUsS0FBSyxDQUFDLHVDQUF1QyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDbEYsT0FBTyxjQUFjLENBQUM7QUFDeEIsQ0FBQztBQUVELE1BQU0sQ0FBQyxLQUFLLFVBQVUsWUFBWSxDQUFDLFFBQWdCLEVBQUUsT0FBNkI7SUFDaEYsTUFBTSxjQUFjLEdBQUcsYUFBYSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUN4RCxJQUFJLEdBQVEsQ0FBQztJQUNiLElBQUksT0FBTyxPQUFPLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDbEMsV0FBVztRQUNYLEdBQUcsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDOUIsS0FBSyxDQUFDLGlDQUFpQyxFQUFFLFFBQVEsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUN4RCxJQUFJLEdBQUcsRUFBRSxVQUFVLEtBQUssSUFBSSxJQUFJLFNBQVMsSUFBSSxHQUFHLEVBQUUsQ0FBQztZQUNqRCxzQkFBc0I7WUFDdEIsSUFBSTtZQUNKLHNCQUFzQjtZQUN0Qix3REFBd0Q7WUFDeEQsSUFBSTtZQUNKLEdBQUcsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDO1FBQ3BCLENBQUM7SUFDSCxDQUFDO1NBQU0sQ0FBQztRQUNOLE1BQU07UUFDTixLQUFLLENBQUMsdUNBQXVDLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDekQsTUFBTSxPQUFPLEdBQUcsYUFBYSxDQUFDLGNBQWMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3pELEdBQUcsR0FBRyxNQUFNLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1QixLQUFLLENBQUMsMkNBQTJDLEVBQUUsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ2xFLElBQUk7UUFDSixxQ0FBcUM7UUFDckMsZ0JBQWdCO1FBQ2hCLFlBQVk7UUFDWiwyQ0FBMkM7UUFDM0MsSUFBSTtRQUNKLElBQUksR0FBRyxFQUFFLFVBQVUsS0FBSyxJQUFJLElBQUksR0FBRyxFQUFFLE9BQU8sRUFBRSxVQUFVLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDbEUsc0JBQXNCO1lBQ3RCLElBQUk7WUFDSixzQkFBc0I7WUFDdEIsZUFBZTtZQUNmLHdCQUF3QjtZQUN4QixpQkFBaUI7WUFDakIsMERBQTBEO1lBQzFELG9CQUFvQjtZQUNwQixlQUFlO1lBQ2YsUUFBUTtZQUNSLE9BQU87WUFDUCwyQ0FBMkM7WUFDM0MsSUFBSTtZQUNKLEdBQUcsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDO1FBQ3BCLENBQUM7UUFDRCxJQUFJLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxDQUFDO1lBQy9CLElBQUksU0FBUyxJQUFJLEdBQUcsRUFBRSxDQUFDO2dCQUNyQixHQUFHLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQztZQUNwQixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFDRCxLQUFLLENBQUMsZ0NBQWdDLEVBQUUsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyJ9
@@ -0,0 +1,15 @@
1
+ import { getFrameworkPath } from './framework.js';
2
+ import { getPlugins, getConfig, getLoadUnits } from './plugin.js';
3
+ import { getFrameworkOrEggPath } from './deprecated.js';
4
+ export { getFrameworkPath } from './framework.js';
5
+ export { getPlugins, getConfig, getLoadUnits } from './plugin.js';
6
+ export { getFrameworkOrEggPath } from './deprecated.js';
7
+ export * from './import.js';
8
+ declare const _default: {
9
+ getFrameworkPath: typeof getFrameworkPath;
10
+ getPlugins: typeof getPlugins;
11
+ getConfig: typeof getConfig;
12
+ getLoadUnits: typeof getLoadUnits;
13
+ getFrameworkOrEggPath: typeof getFrameworkOrEggPath;
14
+ };
15
+ export default _default;
@@ -0,0 +1,15 @@
1
+ import { getFrameworkPath } from './framework.js';
2
+ import { getPlugins, getConfig, getLoadUnits } from './plugin.js';
3
+ import { getFrameworkOrEggPath } from './deprecated.js';
4
+ // support import { getFrameworkPath } from '@eggjs/utils'
5
+ export { getFrameworkPath } from './framework.js';
6
+ export { getPlugins, getConfig, getLoadUnits } from './plugin.js';
7
+ export { getFrameworkOrEggPath } from './deprecated.js';
8
+ export * from './import.js';
9
+ // support import utils from '@eggjs/utils'
10
+ export default {
11
+ getFrameworkPath,
12
+ getPlugins, getConfig, getLoadUnits,
13
+ getFrameworkOrEggPath,
14
+ };
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xFLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRXhELDBEQUEwRDtBQUMxRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDeEQsY0FBYyxhQUFhLENBQUM7QUFFNUIsMkNBQTJDO0FBQzNDLGVBQWU7SUFDYixnQkFBZ0I7SUFDaEIsVUFBVSxFQUFFLFNBQVMsRUFBRSxZQUFZO0lBQ25DLHFCQUFxQjtDQUN0QixDQUFDIn0=
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,30 @@
1
+ export interface LoaderOptions {
2
+ framework: string;
3
+ baseDir: string;
4
+ env?: string;
5
+ }
6
+ export interface Plugin {
7
+ name: string;
8
+ version?: string;
9
+ enable: boolean;
10
+ implicitEnable: boolean;
11
+ path: string;
12
+ dependencies: string[];
13
+ optionalDependencies: string[];
14
+ env: string[];
15
+ from: string;
16
+ }
17
+ /**
18
+ * @see https://github.com/eggjs/egg-core/blob/2920f6eade07959d25f5c4f96b154d3fbae877db/lib/loader/mixin/plugin.js#L203
19
+ */
20
+ export declare function getPlugins(options: LoaderOptions): Promise<Record<string, Plugin>>;
21
+ interface Unit {
22
+ type: 'plugin' | 'framework' | 'app';
23
+ path: string;
24
+ }
25
+ /**
26
+ * @see https://github.com/eggjs/egg-core/blob/2920f6eade07959d25f5c4f96b154d3fbae877db/lib/loader/egg_loader.js#L348
27
+ */
28
+ export declare function getLoadUnits(options: LoaderOptions): Promise<Unit[]>;
29
+ export declare function getConfig(options: LoaderOptions): Promise<Record<string, any>>;
30
+ export {};
@@ -0,0 +1,113 @@
1
+ import { debuglog } from 'node:util';
2
+ import path from 'node:path';
3
+ import assert from 'node:assert';
4
+ import os from 'node:os';
5
+ import { stat, mkdir, writeFile, realpath } from 'node:fs/promises';
6
+ import { importModule } from './import.js';
7
+ const debug = debuglog('@eggjs/utils:plugin');
8
+ const tmpDir = os.tmpdir();
9
+ function noop() { }
10
+ const logger = {
11
+ debug: noop,
12
+ info: noop,
13
+ warn: noop,
14
+ error: noop,
15
+ };
16
+ /**
17
+ * @see https://github.com/eggjs/egg-core/blob/2920f6eade07959d25f5c4f96b154d3fbae877db/lib/loader/mixin/plugin.js#L203
18
+ */
19
+ export async function getPlugins(options) {
20
+ const loader = await getLoader(options);
21
+ await loader.loadPlugin();
22
+ return loader.allPlugins;
23
+ }
24
+ /**
25
+ * @see https://github.com/eggjs/egg-core/blob/2920f6eade07959d25f5c4f96b154d3fbae877db/lib/loader/egg_loader.js#L348
26
+ */
27
+ export async function getLoadUnits(options) {
28
+ const loader = await getLoader(options);
29
+ await loader.loadPlugin();
30
+ return loader.getLoadUnits();
31
+ }
32
+ export async function getConfig(options) {
33
+ const loader = await getLoader(options);
34
+ await loader.loadPlugin();
35
+ await loader.loadConfig();
36
+ return loader.config;
37
+ }
38
+ async function exists(filepath) {
39
+ try {
40
+ await stat(filepath);
41
+ return true;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ async function getLoader(options) {
48
+ assert(options.framework, 'framework is required');
49
+ assert(await exists(options.framework), `${options.framework} should exist`);
50
+ if (!(options.baseDir && await exists(options.baseDir))) {
51
+ options.baseDir = path.join(tmpDir, 'egg_utils', `${Date.now()}`, 'tmp_app');
52
+ await mkdir(options.baseDir, { recursive: true });
53
+ await writeFile(path.join(options.baseDir, 'package.json'), JSON.stringify({
54
+ name: 'tmp_app',
55
+ }));
56
+ debug('[getLoader] create baseDir: %o', options.baseDir);
57
+ }
58
+ const { EggCore, EggLoader } = await findEggCore(options);
59
+ const mod = await importModule(options.framework);
60
+ const Application = mod.Application ?? mod.default?.Application;
61
+ assert(Application, `Application not export on ${options.framework}`);
62
+ if (options.env) {
63
+ process.env.EGG_SERVER_ENV = options.env;
64
+ }
65
+ return new EggLoader({
66
+ baseDir: options.baseDir,
67
+ logger,
68
+ app: Object.create(Application.prototype),
69
+ EggCoreClass: EggCore,
70
+ });
71
+ }
72
+ async function findEggCore(options) {
73
+ const baseDirRealpath = await realpath(options.baseDir);
74
+ const frameworkRealpath = await realpath(options.framework);
75
+ const paths = [frameworkRealpath, baseDirRealpath];
76
+ // custom framework => egg => @eggjs/core
77
+ try {
78
+ const { EggCore, EggLoader } = await importModule('egg', { paths });
79
+ if (EggLoader) {
80
+ return { EggCore, EggLoader };
81
+ }
82
+ }
83
+ catch (err) {
84
+ debug('[findEggCore] import "egg" from paths:%o error: %o', paths, err);
85
+ }
86
+ const name = '@eggjs/core';
87
+ // egg => egg-core
88
+ try {
89
+ const { EggCore, EggLoader } = await importModule(name, { paths });
90
+ if (EggLoader) {
91
+ return { EggCore, EggLoader };
92
+ }
93
+ }
94
+ catch (err) {
95
+ debug('[findEggCore] import "%s" from paths:%o error: %o', name, paths, err);
96
+ }
97
+ try {
98
+ const { EggCore, EggLoader } = await importModule(name);
99
+ if (EggLoader) {
100
+ return { EggCore, EggLoader };
101
+ }
102
+ }
103
+ catch (err) {
104
+ debug('[findEggCore] import "%s" error: %o', name, err);
105
+ }
106
+ let eggCorePath = path.join(options.baseDir, `node_modules/${name}`);
107
+ if (!(await exists(eggCorePath))) {
108
+ eggCorePath = path.join(options.framework, `node_modules/${name}`);
109
+ }
110
+ assert(await exists(eggCorePath), `Can't find ${name} from ${options.baseDir} and ${options.framework}`);
111
+ return await importModule(eggCorePath);
112
+ }
113
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUM3QixPQUFPLE1BQU0sTUFBTSxhQUFhLENBQUM7QUFDakMsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3pCLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNwRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTNDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0FBRTlDLE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQUUzQixTQUFTLElBQUksS0FBSSxDQUFDO0FBRWxCLE1BQU0sTUFBTSxHQUFHO0lBQ2IsS0FBSyxFQUFFLElBQUk7SUFDWCxJQUFJLEVBQUUsSUFBSTtJQUNWLElBQUksRUFBRSxJQUFJO0lBQ1YsS0FBSyxFQUFFLElBQUk7Q0FDWixDQUFDO0FBb0JGOztHQUVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxVQUFVLENBQUMsT0FBc0I7SUFDckQsTUFBTSxNQUFNLEdBQUcsTUFBTSxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDeEMsTUFBTSxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7SUFDMUIsT0FBTyxNQUFNLENBQUMsVUFBVSxDQUFDO0FBQzNCLENBQUM7QUFPRDs7R0FFRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsWUFBWSxDQUFDLE9BQXNCO0lBQ3ZELE1BQU0sTUFBTSxHQUFHLE1BQU0sU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3hDLE1BQU0sTUFBTSxDQUFDLFVBQVUsRUFBRSxD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
@@ -0,0 +1 @@
1
+ export declare function readJSONSync(file: string): any;
@@ -0,0 +1,8 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ export function readJSONSync(file) {
3
+ if (!existsSync(file)) {
4
+ throw new Error(`${file} is not found`);
5
+ }
6
+ return JSON.parse(readFileSync(file, 'utf-8'));
7
+ }
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFFbkQsTUFBTSxVQUFVLFlBQVksQ0FBQyxJQUFZO0lBQ3ZDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsSUFBSSxlQUFlLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztBQUNqRCxDQUFDIn0=
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "@eggjs/utils",
3
- "version": "3.0.1",
3
+ "version": "4.0.1",
4
+ "engine": {
5
+ "node": ">=18.19.0"
6
+ },
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
4
10
  "description": "Utils for all egg projects",
5
- "main": "lib/index.js",
6
- "types": "lib/index.d.ts",
7
- "files": [
8
- "lib"
9
- ],
10
11
  "scripts": {
11
- "lint": "eslint .",
12
- "pretest": "npm run lint && npm run tsc",
13
- "test": "egg-bin test",
14
- "preci": "npm run lint && npm run tsc",
15
- "ci": "egg-bin cov",
16
- "tsc": "tsc",
17
- "clean": "tsc --build --clean",
18
- "prepublishOnly": "npm run clean && npm run tsc",
19
- "contributor": "git-contributor"
12
+ "lint": "eslint src test --ext ts",
13
+ "pretest": "npm run prepublishOnly",
14
+ "test": "npm run lint -- --fix && npm run test-local",
15
+ "test-local": "egg-bin test",
16
+ "preci": "npm run prepublishOnly",
17
+ "ci": "npm run lint && egg-bin cov && npm run prepublishOnly",
18
+ "contributor": "git-contributor",
19
+ "prepublishOnly": "tshy && tshy-after"
20
20
  },
21
21
  "keywords": [
22
22
  "egg",
@@ -25,29 +25,52 @@
25
25
  "author": "fengmk2 <fengmk2@gmail.com> (https://github.com/fengmk2)",
26
26
  "repository": {
27
27
  "type": "git",
28
- "url": "https://github.com/eggjs/egg-utils.git"
28
+ "url": "git://github.com/eggjs/egg-utils.git"
29
29
  },
30
30
  "license": "MIT",
31
31
  "dependencies": {},
32
32
  "devDependencies": {
33
- "@eggjs/tsconfig": "^1.3.3",
34
- "@types/mocha": "^10.0.1",
35
- "@types/node": "^20.2.5",
36
- "coffee": "^5.5.0",
37
- "egg-bin": "^6.4.0",
38
- "eslint": "^8.41.0",
39
- "eslint-config-egg": "^12.2.1",
40
- "git-contributor": "^2.1.5",
41
- "mm": "^3.3.0",
42
- "npm": "^9.6.7",
43
- "npminstall": "^7.9.0",
44
- "runscript": "^1.5.3",
45
- "typescript": "^5.0.4"
33
+ "@eggjs/tsconfig": "1",
34
+ "@types/mocha": "10",
35
+ "@types/node": "20",
36
+ "coffee": "5",
37
+ "egg-bin": "6",
38
+ "eslint": "8",
39
+ "eslint-config-egg": "13",
40
+ "git-contributor": "2",
41
+ "mm": "3",
42
+ "npminstall": "7",
43
+ "runscript": "1",
44
+ "tshy": "1",
45
+ "tshy-after": "1",
46
+ "typescript": "5"
46
47
  },
47
- "engine": {
48
- "node": ">=16.13.0"
48
+ "files": [
49
+ "dist",
50
+ "src"
51
+ ],
52
+ "type": "module",
53
+ "tshy": {
54
+ "exports": {
55
+ "./package.json": "./package.json",
56
+ ".": "./src/index.ts"
57
+ }
49
58
  },
50
- "publishConfig": {
51
- "access": "public"
52
- }
59
+ "exports": {
60
+ "./package.json": "./package.json",
61
+ ".": {
62
+ "import": {
63
+ "source": "./src/index.ts",
64
+ "types": "./dist/esm/index.d.ts",
65
+ "default": "./dist/esm/index.js"
66
+ },
67
+ "require": {
68
+ "source": "./src/index.ts",
69
+ "types": "./dist/commonjs/index.d.ts",
70
+ "default": "./dist/commonjs/index.js"
71
+ }
72
+ }
73
+ },
74
+ "main": "./dist/commonjs/index.js",
75
+ "types": "./dist/commonjs/index.d.ts"
53
76
  }
@@ -0,0 +1,58 @@
1
+ import path from 'node:path';
2
+ import { existsSync, readdirSync } from 'node:fs';
3
+ import { readJSONSync } from './utils.js';
4
+
5
+ /**
6
+ * Try to get framework dir path
7
+ * If can't find any framework, try to find egg dir path
8
+ *
9
+ * @param {String} cwd - current work path
10
+ * @param {Array} [eggNames] - egg names, default is ['egg']
11
+ * @return {String} framework or egg dir path
12
+ * @deprecated
13
+ */
14
+ export function getFrameworkOrEggPath(cwd: string, eggNames?: string[]): string {
15
+ eggNames = eggNames || [ 'egg' ];
16
+ const moduleDir = path.join(cwd, 'node_modules');
17
+ if (!existsSync(moduleDir)) {
18
+ return '';
19
+ }
20
+
21
+ // try to get framework
22
+
23
+ // 1. try to read egg.framework property on package.json
24
+ const pkgFile = path.join(cwd, 'package.json');
25
+ if (existsSync(pkgFile)) {
26
+ const pkg = readJSONSync(pkgFile);
27
+ if (pkg.egg && pkg.egg.framework) {
28
+ return path.join(moduleDir, pkg.egg.framework);
29
+ }
30
+ }
31
+
32
+ // 2. try the module dependencies includes eggNames
33
+ const names = readdirSync(moduleDir);
34
+ for (const name of names) {
35
+ const pkgfile = path.join(moduleDir, name, 'package.json');
36
+ if (!existsSync(pkgfile)) {
37
+ continue;
38
+ }
39
+ const pkg = readJSONSync(pkgfile);
40
+ if (pkg.dependencies) {
41
+ for (const eggName of eggNames) {
42
+ if (pkg.dependencies[eggName]) {
43
+ return path.join(moduleDir, name);
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ // try to get egg
50
+ for (const eggName of eggNames) {
51
+ const pkgfile = path.join(moduleDir, eggName, 'package.json');
52
+ if (existsSync(pkgfile)) {
53
+ return path.join(moduleDir, eggName);
54
+ }
55
+ }
56
+
57
+ return '';
58
+ }
@@ -0,0 +1,87 @@
1
+ import path from 'node:path';
2
+ import assert from 'node:assert';
3
+ import { existsSync } from 'node:fs';
4
+ import { readJSONSync } from './utils.js';
5
+
6
+ const initCwd = process.cwd();
7
+
8
+ interface Options {
9
+ baseDir: string;
10
+ framework?: string;
11
+ }
12
+
13
+ /**
14
+ * Find the framework directory, lookup order
15
+ * - specify framework path
16
+ * - get framework name from
17
+ * - use egg by default
18
+ * @param {Object} options - options
19
+ * @param {String} options.baseDir - the current directory of application
20
+ * @param {String} [options.framework] - the directory of framework
21
+ * @return {String} frameworkPath
22
+ */
23
+ export function getFrameworkPath(options: Options): string {
24
+ const { framework, baseDir } = options;
25
+ const pkgPath = path.join(baseDir, 'package.json');
26
+ assert(existsSync(pkgPath), `${pkgPath} should exist`);
27
+ const moduleDir = path.join(baseDir, 'node_modules');
28
+
29
+ // 1. pass framework or customEgg
30
+ if (framework) {
31
+ // 1.1 framework is an absolute path
32
+ // framework: path.join(baseDir, 'node_modules/${frameworkName}')
33
+ if (path.isAbsolute(framework)) {
34
+ assert(existsSync(framework), `${framework} should exist`);
35
+ return framework;
36
+ }
37
+ // 1.2 framework is a npm package that required by application
38
+ // framework: 'frameworkName'
39
+ return assertAndReturn(framework, moduleDir);
40
+ }
41
+
42
+ const pkg = readJSONSync(pkgPath);
43
+ // 2. framework is not specified
44
+ // 2.1 use framework name from pkg.egg.framework
45
+ if (pkg.egg?.framework) {
46
+ return assertAndReturn(pkg.egg.framework, moduleDir);
47
+ }
48
+
49
+ // 2.2 use egg by default
50
+ return assertAndReturn('egg', moduleDir);
51
+ }
52
+
53
+ function assertAndReturn(frameworkName: string, moduleDir: string) {
54
+ const moduleDirs = new Set([
55
+ moduleDir,
56
+ // find framework from process.cwd, especially for test,
57
+ // the application is in test/fixtures/app,
58
+ // and framework is install in ${cwd}/node_modules
59
+ path.join(process.cwd(), 'node_modules'),
60
+ // prevent from mocking process.cwd
61
+ path.join(initCwd, 'node_modules'),
62
+ ]);
63
+ try {
64
+ // find framework from global, especially for monorepo
65
+ let globalModuleDir;
66
+ // if frameworkName is scoped package, like @ali/egg
67
+ if (frameworkName.startsWith('@') && frameworkName.includes('/')) {
68
+ globalModuleDir = path.join(
69
+ require.resolve(`${frameworkName}/package.json`),
70
+ '../../..',
71
+ );
72
+ } else {
73
+ globalModuleDir = path.join(
74
+ require.resolve(`${frameworkName}/package.json`),
75
+ '../..',
76
+ );
77
+ }
78
+ moduleDirs.add(globalModuleDir);
79
+ } catch (err) {
80
+ // ignore
81
+ }
82
+ for (const moduleDir of moduleDirs) {
83
+ const frameworkPath = path.join(moduleDir, frameworkName);
84
+ if (existsSync(frameworkPath)) return frameworkPath;
85
+ }
86
+ throw new Error(`${frameworkName} is not found in ${Array.from(moduleDirs)}`);
87
+ }
package/src/import.ts ADDED
@@ -0,0 +1,82 @@
1
+ import { debuglog } from 'node:util';
2
+ import { createRequire } from 'node:module';
3
+ import { pathToFileURL } from 'node:url';
4
+
5
+ const debug = debuglog('@eggjs/utils:loader');
6
+
7
+ let _customRequire: NodeRequire;
8
+
9
+ export interface ImportResolveOptions {
10
+ paths?: string[];
11
+ }
12
+
13
+ export interface ImportModuleOptions extends ImportResolveOptions {
14
+ // only import export default object
15
+ importDefaultOnly?: boolean;
16
+ }
17
+
18
+ export function importResolve(filepath: string, options?: ImportResolveOptions) {
19
+ if (!_customRequire) {
20
+ if (typeof require !== 'undefined') {
21
+ _customRequire = require;
22
+ } else {
23
+ _customRequire = createRequire(process.cwd());
24
+ }
25
+ }
26
+ const moduleFilePath = _customRequire.resolve(filepath, options);
27
+ debug('[importResolve] %o, options: %o => %o', filepath, options, moduleFilePath);
28
+ return moduleFilePath;
29
+ }
30
+
31
+ export async function importModule(filepath: string, options?: ImportModuleOptions) {
32
+ const moduleFilePath = importResolve(filepath, options);
33
+ let obj: any;
34
+ if (typeof require === 'function') {
35
+ // commonjs
36
+ obj = require(moduleFilePath);
37
+ debug('[importModule] require %o => %o', filepath, obj);
38
+ if (obj?.__esModule === true && 'default' in obj) {
39
+ // 兼容 cjs 模拟 esm 的导出格式
40
+ // {
41
+ // __esModule: true,
42
+ // default: { fn: [Function: fn], foo: 'bar', one: 1 }
43
+ // }
44
+ obj = obj.default;
45
+ }
46
+ } else {
47
+ // esm
48
+ debug('[importModule] await import start: %o', filepath);
49
+ const fileUrl = pathToFileURL(moduleFilePath).toString();
50
+ obj = await import(fileUrl);
51
+ debug('[importModule] await import end: %o => %o', filepath, obj);
52
+ // {
53
+ // default: { foo: 'bar', one: 1 },
54
+ // foo: 'bar',
55
+ // one: 1,
56
+ // [Symbol(Symbol.toStringTag)]: 'Module'
57
+ // }
58
+ if (obj?.__esModule === true && obj?.default?.__esModule === true) {
59
+ // 兼容 cjs 模拟 esm 的导出格式
60
+ // {
61
+ // __esModule: true,
62
+ // default: {
63
+ // __esModule: true,
64
+ // default: {
65
+ // fn: [Function: fn] { [length]: 0, [name]: 'fn' },
66
+ // foo: 'bar',
67
+ // one: 1
68
+ // }
69
+ // },
70
+ // [Symbol(Symbol.toStringTag)]: 'Module'
71
+ // }
72
+ obj = obj.default;
73
+ }
74
+ if (options?.importDefaultOnly) {
75
+ if ('default' in obj) {
76
+ obj = obj.default;
77
+ }
78
+ }
79
+ }
80
+ debug('[importModule] return %o => %o', filepath, obj);
81
+ return obj;
82
+ }
package/src/index.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { getFrameworkPath } from './framework.js';
2
+ import { getPlugins, getConfig, getLoadUnits } from './plugin.js';
3
+ import { getFrameworkOrEggPath } from './deprecated.js';
4
+
5
+ // support import { getFrameworkPath } from '@eggjs/utils'
6
+ export { getFrameworkPath } from './framework.js';
7
+ export { getPlugins, getConfig, getLoadUnits } from './plugin.js';
8
+ export { getFrameworkOrEggPath } from './deprecated.js';
9
+ export * from './import.js';
10
+
11
+ // support import utils from '@eggjs/utils'
12
+ export default {
13
+ getFrameworkPath,
14
+ getPlugins, getConfig, getLoadUnits,
15
+ getFrameworkOrEggPath,
16
+ };