@eggjs/core 7.0.2-beta.1 → 7.0.2-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/egg.d.ts +25 -0
- package/dist/egg.js +21 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.js +6 -1
- package/dist/lifecycle.d.ts +62 -1
- package/dist/lifecycle.js +131 -8
- package/dist/loader/egg_loader.d.ts +15 -0
- package/dist/loader/egg_loader.js +180 -17
- package/dist/loader/file_loader.d.ts +10 -3
- package/dist/loader/file_loader.js +16 -8
- package/dist/loader/loader_fs.d.ts +17 -0
- package/dist/loader/loader_fs.js +271 -0
- package/dist/loader/manifest.d.ts +98 -0
- package/dist/loader/manifest.js +341 -0
- package/package.json +12 -9
|
@@ -3,6 +3,7 @@ import { sequencify } from "../utils/sequencify.js";
|
|
|
3
3
|
import { Timing } from "../utils/timing.js";
|
|
4
4
|
import { CaseStyle, FULLPATH, FileLoader } from "./file_loader.js";
|
|
5
5
|
import { ContextLoader } from "./context_loader.js";
|
|
6
|
+
import { ManifestStore } from "./manifest.js";
|
|
6
7
|
import fs from "node:fs";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
import { debuglog, inspect } from "node:util";
|
|
@@ -11,14 +12,35 @@ import assert from "node:assert";
|
|
|
11
12
|
import { Application, Context, Request, Response } from "@eggjs/koa";
|
|
12
13
|
import { isAsyncFunction, isClass, isGeneratorFunction, isObject, isPromise } from "is-type-of";
|
|
13
14
|
import { extend } from "@eggjs/extend2";
|
|
15
|
+
import { RealLoaderFS } from "@eggjs/loader-fs";
|
|
14
16
|
import { pathMatching } from "@eggjs/path-matching";
|
|
17
|
+
import globby from "globby";
|
|
15
18
|
import { homedir } from "node-homedir";
|
|
16
19
|
import { diff, now } from "performance-ms";
|
|
17
20
|
import { register } from "tsconfig-paths";
|
|
18
|
-
import {
|
|
21
|
+
import { getParamNames } from "utility";
|
|
19
22
|
|
|
20
23
|
//#region src/loader/egg_loader.ts
|
|
21
24
|
const debug = debuglog("egg/core/loader/egg_loader");
|
|
25
|
+
const CONVENTIONAL_MANIFEST_LOADS = [
|
|
26
|
+
{
|
|
27
|
+
type: "resolve",
|
|
28
|
+
path: ["agent"]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: "resolve",
|
|
32
|
+
path: ["app"]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: "discover",
|
|
36
|
+
path: ["app", "extend"],
|
|
37
|
+
extensionlessResolve: true
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: "discover",
|
|
41
|
+
path: ["app", "middleware"]
|
|
42
|
+
}
|
|
43
|
+
];
|
|
22
44
|
const originalPrototypes = {
|
|
23
45
|
request: Request.prototype,
|
|
24
46
|
response: Response.prototype,
|
|
@@ -34,7 +56,11 @@ var EggLoader = class {
|
|
|
34
56
|
serverEnv;
|
|
35
57
|
serverScope;
|
|
36
58
|
appInfo;
|
|
59
|
+
outDir;
|
|
37
60
|
dirs;
|
|
61
|
+
/** Startup manifest — loaded from cache or collecting for generation */
|
|
62
|
+
manifest;
|
|
63
|
+
loaderFS;
|
|
38
64
|
/**
|
|
39
65
|
* @class
|
|
40
66
|
* @param {Object} options - options
|
|
@@ -46,6 +72,7 @@ var EggLoader = class {
|
|
|
46
72
|
*/
|
|
47
73
|
constructor(options) {
|
|
48
74
|
this.options = options;
|
|
75
|
+
this.loaderFS = this.options.loaderFS ?? new RealLoaderFS();
|
|
49
76
|
assert(fs.existsSync(this.options.baseDir), `${this.options.baseDir} not exists`);
|
|
50
77
|
assert(this.options.app, "options.app is required");
|
|
51
78
|
assert(this.options.logger, "options.logger is required");
|
|
@@ -55,7 +82,8 @@ var EggLoader = class {
|
|
|
55
82
|
* @see {@link AppInfo#pkg}
|
|
56
83
|
* @since 1.0.0
|
|
57
84
|
*/
|
|
58
|
-
this.pkg =
|
|
85
|
+
this.pkg = this.loaderFS.readJSON(path.join(this.options.baseDir, "package.json"));
|
|
86
|
+
this.outDir = this.#resolveOutDir();
|
|
59
87
|
if (process.env.EGG_TYPESCRIPT === "true" || this.pkg.egg && this.pkg.egg.typescript) {
|
|
60
88
|
const tsConfigFile = path.join(this.options.baseDir, "tsconfig.json");
|
|
61
89
|
if (fs.existsSync(tsConfigFile)) register({ cwd: this.options.baseDir });
|
|
@@ -102,6 +130,7 @@ var EggLoader = class {
|
|
|
102
130
|
* @since 1.0.0
|
|
103
131
|
*/
|
|
104
132
|
this.appInfo = this.getAppInfo();
|
|
133
|
+
this.manifest = ManifestStore.load(this.options.baseDir, this.serverEnv, this.serverScope) ?? ManifestStore.createCollector(this.options.baseDir);
|
|
105
134
|
}
|
|
106
135
|
get app() {
|
|
107
136
|
return this.options.app;
|
|
@@ -382,17 +411,14 @@ var EggLoader = class {
|
|
|
382
411
|
let pkg;
|
|
383
412
|
let eggPluginConfig;
|
|
384
413
|
const pluginPackage = path.join(plugin.path, "package.json");
|
|
385
|
-
if (
|
|
386
|
-
pkg = await
|
|
414
|
+
if (this.loaderFS.exists(pluginPackage)) {
|
|
415
|
+
pkg = await this.loaderFS.loadFile(pluginPackage);
|
|
387
416
|
eggPluginConfig = pkg.eggPlugin;
|
|
388
417
|
if (pkg.version) plugin.version = pkg.version;
|
|
389
418
|
plugin.path = await this.#formatPluginPathFromPackageJSON(plugin.path, pkg);
|
|
390
419
|
}
|
|
420
|
+
if (!eggPluginConfig) return;
|
|
391
421
|
const logger = this.options.logger;
|
|
392
|
-
if (!eggPluginConfig) {
|
|
393
|
-
logger.warn("[@eggjs/core/egg_loader] pkg.eggPlugin is missing in %s, plugin: %j", pluginPackage, plugin);
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
422
|
if (eggPluginConfig.name && eggPluginConfig.strict !== false && eggPluginConfig.name !== plugin.name) logger.warn(`[@eggjs/core/egg_loader] pluginName(${plugin.name}) is different from pluginConfigName(${eggPluginConfig.name})`);
|
|
397
423
|
depCompatible(eggPluginConfig);
|
|
398
424
|
for (const key of [
|
|
@@ -455,10 +481,45 @@ var EggLoader = class {
|
|
|
455
481
|
return lookupDirs;
|
|
456
482
|
}
|
|
457
483
|
getPluginPath(plugin) {
|
|
458
|
-
if (plugin.path) return plugin.path;
|
|
484
|
+
if (plugin.path && !this.#isBundlePluginPathArtifact(plugin.path)) return plugin.path;
|
|
459
485
|
if (plugin.package) assert(isValidatePackageName(plugin.package), `plugin ${plugin.name} invalid, use 'path' instead of package: "${plugin.package}"`);
|
|
486
|
+
if (plugin.path && this.#isBundlePluginPathArtifact(plugin.path)) return this.#resolveBundlePluginPath(plugin);
|
|
460
487
|
return this.#resolvePluginPath(plugin);
|
|
461
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* In bundle mode a plugin declared via `definePluginFactory({ path: import.meta.dirname })`
|
|
491
|
+
* carries a `path` rewritten by the bundler to the bundle output directory (= baseDir),
|
|
492
|
+
* which does not contain the plugin's own files. Detect that case so the plugin is
|
|
493
|
+
* re-resolved by package name instead.
|
|
494
|
+
*/
|
|
495
|
+
#isBundlePluginPathArtifact(pluginPath) {
|
|
496
|
+
const bundleStore = ManifestStore.getBundleStore();
|
|
497
|
+
if (!bundleStore || path.resolve(bundleStore.baseDir) !== path.resolve(this.options.baseDir)) return false;
|
|
498
|
+
return path.resolve(pluginPath) === path.resolve(this.options.baseDir);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Re-resolve a bundle-artifact plugin path to the directory of the plugin package's entry
|
|
502
|
+
* module — the same directory `definePluginFactory` captured via `import.meta.dirname` at
|
|
503
|
+
* build time. Built-in framework plugins only carry a `name` (no `package`), so fall back to
|
|
504
|
+
* the conventional `@eggjs/<name>` package name in addition to the bare name.
|
|
505
|
+
*/
|
|
506
|
+
#resolveBundlePluginPath(plugin) {
|
|
507
|
+
const candidates = plugin.package ? [plugin.package] : plugin.name.includes("/") ? [plugin.name] : [plugin.name, `@eggjs/${plugin.name}`];
|
|
508
|
+
let lastErr;
|
|
509
|
+
for (const name$1 of candidates) try {
|
|
510
|
+
const entry = utils_default.resolvePath(name$1, { paths: [...this.lookupDirs] });
|
|
511
|
+
const realDir = path.dirname(entry);
|
|
512
|
+
const segments = realDir.split(/[/\\]/);
|
|
513
|
+
const nmIdx = segments.lastIndexOf("node_modules");
|
|
514
|
+
if (nmIdx !== -1) return path.join(this.options.baseDir, ...segments.slice(nmIdx));
|
|
515
|
+
return realDir;
|
|
516
|
+
} catch (err) {
|
|
517
|
+
lastErr = err;
|
|
518
|
+
}
|
|
519
|
+
const name = plugin.package || plugin.name;
|
|
520
|
+
debug("[resolveBundlePluginPath] error: %o, plugin info: %o", lastErr, plugin);
|
|
521
|
+
throw new Error(`Can not find plugin ${name} in "${[...this.lookupDirs].join(", ")}"`, { cause: lastErr });
|
|
522
|
+
}
|
|
462
523
|
#resolvePluginPath(plugin) {
|
|
463
524
|
const name = plugin.package || plugin.name;
|
|
464
525
|
try {
|
|
@@ -476,7 +537,7 @@ var EggLoader = class {
|
|
|
476
537
|
if (isESM) {
|
|
477
538
|
if (exports.import) realPluginPath = path.join(pluginPath, exports.import);
|
|
478
539
|
} else if (exports.require) realPluginPath = path.join(pluginPath, exports.require);
|
|
479
|
-
if (exports.typescript && isSupportTypeScript() && !
|
|
540
|
+
if (exports.typescript && isSupportTypeScript() && !this.loaderFS.exists(realPluginPath)) {
|
|
480
541
|
realPluginPath = path.join(pluginPath, exports.typescript);
|
|
481
542
|
debug("[formatPluginPathFromPackageJSON] use typescript path %o", realPluginPath);
|
|
482
543
|
}
|
|
@@ -742,14 +803,16 @@ var EggLoader = class {
|
|
|
742
803
|
*/
|
|
743
804
|
async loadCustomApp() {
|
|
744
805
|
await this.#loadBootHook("app");
|
|
745
|
-
this.lifecycle.
|
|
806
|
+
if (this.options.metadataOnly) await this.lifecycle.triggerLoadMetadata();
|
|
807
|
+
else this.lifecycle.triggerConfigWillLoad();
|
|
746
808
|
}
|
|
747
809
|
/**
|
|
748
810
|
* Load agent.js, same as {@link EggLoader#loadCustomApp}
|
|
749
811
|
*/
|
|
750
812
|
async loadCustomAgent() {
|
|
751
813
|
await this.#loadBootHook("agent");
|
|
752
|
-
this.lifecycle.
|
|
814
|
+
if (this.options.metadataOnly) await this.lifecycle.triggerLoadMetadata();
|
|
815
|
+
else this.lifecycle.triggerConfigWillLoad();
|
|
753
816
|
}
|
|
754
817
|
loadBootHook() {}
|
|
755
818
|
async #loadBootHook(fileName) {
|
|
@@ -1042,7 +1105,9 @@ var EggLoader = class {
|
|
|
1042
1105
|
...options,
|
|
1043
1106
|
directory: options?.directory ?? directory,
|
|
1044
1107
|
target,
|
|
1045
|
-
inject: this.app
|
|
1108
|
+
inject: this.app,
|
|
1109
|
+
manifest: this.manifest,
|
|
1110
|
+
loaderFS: options?.loaderFS ?? this.loaderFS
|
|
1046
1111
|
};
|
|
1047
1112
|
const timingKey = `Load "${String(property)}" to Application`;
|
|
1048
1113
|
this.timing.start(timingKey);
|
|
@@ -1061,7 +1126,9 @@ var EggLoader = class {
|
|
|
1061
1126
|
...options,
|
|
1062
1127
|
directory: options?.directory || directory,
|
|
1063
1128
|
property,
|
|
1064
|
-
inject: this.app
|
|
1129
|
+
inject: this.app,
|
|
1130
|
+
manifest: this.manifest,
|
|
1131
|
+
loaderFS: options?.loaderFS ?? this.loaderFS
|
|
1065
1132
|
};
|
|
1066
1133
|
const timingKey = `Load "${String(property)}" to Context`;
|
|
1067
1134
|
this.timing.start(timingKey);
|
|
@@ -1091,14 +1158,110 @@ var EggLoader = class {
|
|
|
1091
1158
|
return files;
|
|
1092
1159
|
}
|
|
1093
1160
|
resolveModule(filepath) {
|
|
1161
|
+
return this.manifest.resolveModule(filepath, () => this.#doResolveModule(filepath));
|
|
1162
|
+
}
|
|
1163
|
+
#doResolveModule(filepath) {
|
|
1094
1164
|
let fullPath;
|
|
1095
1165
|
try {
|
|
1096
1166
|
fullPath = utils_default.resolvePath(filepath);
|
|
1097
|
-
} catch {
|
|
1098
|
-
|
|
1099
|
-
}
|
|
1167
|
+
} catch {}
|
|
1168
|
+
if (!fullPath) fullPath = this.#resolveFromOutDir(filepath);
|
|
1100
1169
|
return fullPath;
|
|
1101
1170
|
}
|
|
1171
|
+
#resolveOutDir() {
|
|
1172
|
+
if (this.pkg.egg?.outDir) {
|
|
1173
|
+
debug("[resolveOutDir] use pkg.egg.outDir: %o", this.pkg.egg.outDir);
|
|
1174
|
+
return this.pkg.egg.outDir;
|
|
1175
|
+
}
|
|
1176
|
+
const tsConfigFile = path.join(this.options.baseDir, "tsconfig.json");
|
|
1177
|
+
if (fs.existsSync(tsConfigFile)) try {
|
|
1178
|
+
const tsConfig = JSON.parse(fs.readFileSync(tsConfigFile, "utf-8"));
|
|
1179
|
+
if (tsConfig.compilerOptions?.outDir) {
|
|
1180
|
+
debug("[resolveOutDir] use tsconfig.json compilerOptions.outDir: %o", tsConfig.compilerOptions.outDir);
|
|
1181
|
+
return tsConfig.compilerOptions.outDir;
|
|
1182
|
+
}
|
|
1183
|
+
} catch {}
|
|
1184
|
+
}
|
|
1185
|
+
#resolveFromOutDir(filepath) {
|
|
1186
|
+
if (!this.outDir) return;
|
|
1187
|
+
const baseDir = this.options.baseDir;
|
|
1188
|
+
if (!filepath.startsWith(baseDir + path.sep)) return;
|
|
1189
|
+
const relativePath = path.relative(baseDir, filepath);
|
|
1190
|
+
for (const ext of [".js", ".mjs"]) {
|
|
1191
|
+
const outDirPath = path.join(baseDir, this.outDir, relativePath + ext);
|
|
1192
|
+
if (fs.existsSync(outDirPath)) {
|
|
1193
|
+
debug("[resolveModule:outDir] %o => %o", filepath, outDirPath);
|
|
1194
|
+
return outDirPath;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* Generate startup manifest from collected data.
|
|
1200
|
+
* Should be called after all loading phases complete.
|
|
1201
|
+
*/
|
|
1202
|
+
generateManifest() {
|
|
1203
|
+
const manifest = this.manifest.generateManifest({
|
|
1204
|
+
serverEnv: this.serverEnv,
|
|
1205
|
+
serverScope: this.serverScope,
|
|
1206
|
+
typescriptEnabled: isSupportTypeScript()
|
|
1207
|
+
});
|
|
1208
|
+
this.#collectConventionalDynamicFiles(manifest);
|
|
1209
|
+
return manifest;
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* metadataOnly startup intentionally skips the agent process, but bundled
|
|
1213
|
+
* single-mode workers still load agent boot hooks and agent extends later.
|
|
1214
|
+
* Record convention-based dynamic entry points so the bundle can satisfy
|
|
1215
|
+
* those runtime lookups without running agent lifecycle hooks at manifest
|
|
1216
|
+
* generation time.
|
|
1217
|
+
*/
|
|
1218
|
+
#collectConventionalDynamicFiles(manifest) {
|
|
1219
|
+
const resolveCacheTargets = new Set(Object.values(manifest.resolveCache).filter((target) => typeof target === "string"));
|
|
1220
|
+
for (const unit of this.getLoadUnits()) {
|
|
1221
|
+
this.#collectConventionFile(manifest, path.join(unit.path, "package.json"), resolveCacheTargets);
|
|
1222
|
+
for (const load of CONVENTIONAL_MANIFEST_LOADS) {
|
|
1223
|
+
const target = path.join(unit.path, ...load.path);
|
|
1224
|
+
if (load.type === "resolve") this.#collectConventionResolve(manifest, target, resolveCacheTargets);
|
|
1225
|
+
else if ("extensionlessResolve" in load && load.extensionlessResolve) this.#collectConventionFileResolves(manifest, target, resolveCacheTargets);
|
|
1226
|
+
else this.#collectConventionFileDiscovery(manifest, target);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
#collectConventionResolve(manifest, request, resolveCacheTargets) {
|
|
1231
|
+
const requestKey = this.#toManifestRel(request);
|
|
1232
|
+
if (Object.hasOwn(manifest.resolveCache, requestKey)) return;
|
|
1233
|
+
const resolved = this.#doResolveModule(request);
|
|
1234
|
+
const resolvedKey = resolved ? this.#toManifestRel(resolved) : null;
|
|
1235
|
+
manifest.resolveCache[requestKey] = resolvedKey;
|
|
1236
|
+
if (resolvedKey !== null) resolveCacheTargets.add(resolvedKey);
|
|
1237
|
+
}
|
|
1238
|
+
#collectConventionFileResolves(manifest, directory, resolveCacheTargets) {
|
|
1239
|
+
const files = this.#collectConventionFileDiscovery(manifest, directory);
|
|
1240
|
+
for (const file of files) {
|
|
1241
|
+
const ext = path.extname(file);
|
|
1242
|
+
if (!ext) continue;
|
|
1243
|
+
const request = path.join(directory, file.slice(0, -ext.length));
|
|
1244
|
+
this.#collectConventionResolve(manifest, request, resolveCacheTargets);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
#collectConventionFileDiscovery(manifest, directory) {
|
|
1248
|
+
const dirKey = this.#toManifestRel(directory);
|
|
1249
|
+
if (Object.hasOwn(manifest.fileDiscovery, dirKey)) return manifest.fileDiscovery[dirKey];
|
|
1250
|
+
manifest.fileDiscovery[dirKey] = fs.existsSync(directory) && fs.statSync(directory).isDirectory() ? globby.sync(FileLoader.getDefaultMatch(), { cwd: directory }).sort() : [];
|
|
1251
|
+
return manifest.fileDiscovery[dirKey];
|
|
1252
|
+
}
|
|
1253
|
+
#collectConventionFile(manifest, filepath, resolveCacheTargets) {
|
|
1254
|
+
const fileKey = this.#toManifestRel(filepath);
|
|
1255
|
+
if (resolveCacheTargets.has(fileKey)) return;
|
|
1256
|
+
if (!fs.existsSync(filepath) || !fs.statSync(filepath).isFile()) return;
|
|
1257
|
+
const dirKey = this.#toManifestRel(path.dirname(filepath));
|
|
1258
|
+
const basename = path.basename(filepath);
|
|
1259
|
+
const files = manifest.fileDiscovery[dirKey] ?? [];
|
|
1260
|
+
if (!files.includes(basename)) manifest.fileDiscovery[dirKey] = [...files, basename].sort();
|
|
1261
|
+
}
|
|
1262
|
+
#toManifestRel(filepath) {
|
|
1263
|
+
return (path.isAbsolute(filepath) ? path.relative(this.options.baseDir, filepath) : filepath).replaceAll(path.sep, "/");
|
|
1264
|
+
}
|
|
1102
1265
|
};
|
|
1103
1266
|
function depCompatible(plugin) {
|
|
1104
1267
|
if (plugin.dep && !(Array.isArray(plugin.dependencies) && plugin.dependencies.length > 0)) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ManifestStore } from "./manifest.js";
|
|
2
|
+
import { LoaderFS } from "@eggjs/loader-fs";
|
|
2
3
|
|
|
3
4
|
//#region src/loader/file_loader.d.ts
|
|
4
5
|
declare const FULLPATH: unique symbol;
|
|
@@ -37,12 +38,17 @@ interface FileLoaderOptions {
|
|
|
37
38
|
/** set property's case when converting a filepath to property list. */
|
|
38
39
|
caseStyle?: CaseStyle | CaseStyleFunction;
|
|
39
40
|
lowercaseFirst?: boolean;
|
|
41
|
+
/** Startup manifest for caching globby scans and collecting results */
|
|
42
|
+
manifest?: ManifestStore;
|
|
43
|
+
/** Loader-facing filesystem abstraction */
|
|
44
|
+
loaderFS?: LoaderFS;
|
|
40
45
|
}
|
|
41
46
|
interface FileLoaderParseItem {
|
|
42
47
|
fullpath: string;
|
|
43
48
|
properties: string[];
|
|
44
|
-
exports:
|
|
49
|
+
exports: unknown;
|
|
45
50
|
}
|
|
51
|
+
type NormalizedFileLoaderOptions = FileLoaderOptions & Required<Pick<FileLoaderOptions, "caseStyle" | "loaderFS">>;
|
|
46
52
|
/**
|
|
47
53
|
* Load files from directory to target object.
|
|
48
54
|
* @since 1.0.0
|
|
@@ -50,7 +56,8 @@ interface FileLoaderParseItem {
|
|
|
50
56
|
declare class FileLoader {
|
|
51
57
|
static get FULLPATH(): typeof FULLPATH;
|
|
52
58
|
static get EXPORTS(): typeof EXPORTS;
|
|
53
|
-
|
|
59
|
+
static getDefaultMatch(): string[];
|
|
60
|
+
readonly options: NormalizedFileLoaderOptions;
|
|
54
61
|
/**
|
|
55
62
|
* @class
|
|
56
63
|
* @param {Object} options - options
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import utils_default from "../utils/index.js";
|
|
2
|
-
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { debuglog } from "node:util";
|
|
5
4
|
import { isSupportTypeScript } from "@eggjs/utils";
|
|
6
5
|
import assert from "node:assert";
|
|
7
6
|
import { isAsyncFunction, isClass, isGeneratorFunction, isPrimitive } from "is-type-of";
|
|
8
|
-
import
|
|
7
|
+
import { RealLoaderFS } from "@eggjs/loader-fs";
|
|
9
8
|
|
|
10
9
|
//#region src/loader/file_loader.ts
|
|
11
10
|
const debug = debuglog("egg/core/file_loader");
|
|
@@ -16,17 +15,23 @@ const CaseStyle = {
|
|
|
16
15
|
lower: "lower",
|
|
17
16
|
upper: "upper"
|
|
18
17
|
};
|
|
18
|
+
function getDefaultFileLoaderMatch() {
|
|
19
|
+
return isSupportTypeScript() ? ["**/*.(js|ts)", "!**/*.d.ts"] : ["**/*.js"];
|
|
20
|
+
}
|
|
19
21
|
/**
|
|
20
22
|
* Load files from directory to target object.
|
|
21
23
|
* @since 1.0.0
|
|
22
24
|
*/
|
|
23
|
-
var FileLoader = class {
|
|
25
|
+
var FileLoader = class FileLoader {
|
|
24
26
|
static get FULLPATH() {
|
|
25
27
|
return FULLPATH;
|
|
26
28
|
}
|
|
27
29
|
static get EXPORTS() {
|
|
28
30
|
return EXPORTS;
|
|
29
31
|
}
|
|
32
|
+
static getDefaultMatch() {
|
|
33
|
+
return getDefaultFileLoaderMatch();
|
|
34
|
+
}
|
|
30
35
|
options;
|
|
31
36
|
/**
|
|
32
37
|
* @class
|
|
@@ -45,10 +50,12 @@ var FileLoader = class {
|
|
|
45
50
|
constructor(options) {
|
|
46
51
|
assert(options.directory, "options.directory is required");
|
|
47
52
|
assert(options.target, "options.target is required");
|
|
53
|
+
if (!options.manifest && options.inject) options.manifest = options.inject.loader?.manifest;
|
|
48
54
|
this.options = {
|
|
49
55
|
caseStyle: CaseStyle.camel,
|
|
50
56
|
call: true,
|
|
51
57
|
override: false,
|
|
58
|
+
loaderFS: new RealLoaderFS(),
|
|
52
59
|
...options
|
|
53
60
|
};
|
|
54
61
|
if (this.options.lowercaseFirst === true) {
|
|
@@ -114,7 +121,7 @@ var FileLoader = class {
|
|
|
114
121
|
async parse() {
|
|
115
122
|
let files = this.options.match;
|
|
116
123
|
if (files) files = Array.isArray(files) ? files : [files];
|
|
117
|
-
else files =
|
|
124
|
+
else files = FileLoader.getDefaultMatch();
|
|
118
125
|
let ignore = this.options.ignore;
|
|
119
126
|
if (ignore) {
|
|
120
127
|
ignore = Array.isArray(ignore) ? ignore : [ignore];
|
|
@@ -127,11 +134,12 @@ var FileLoader = class {
|
|
|
127
134
|
const items = [];
|
|
128
135
|
debug("[parse] parsing directories: %j", directories);
|
|
129
136
|
for (const directory of directories) {
|
|
130
|
-
const
|
|
131
|
-
|
|
137
|
+
const manifest = this.options.manifest;
|
|
138
|
+
const filepaths = manifest ? manifest.globFiles(directory, () => this.options.loaderFS.glob(files, { cwd: directory })) : this.options.loaderFS.glob(files, { cwd: directory });
|
|
139
|
+
debug("[parse] files: %o, cwd: %o => %o", files, directory, filepaths);
|
|
132
140
|
for (const filepath of filepaths) {
|
|
133
141
|
const fullpath = path.join(directory, filepath);
|
|
134
|
-
if (!
|
|
142
|
+
if (!this.options.loaderFS.stat(fullpath).isFile()) continue;
|
|
135
143
|
if (filepath.endsWith(".js")) {
|
|
136
144
|
const filepathTs = filepath.replace(/\.js$/, ".ts");
|
|
137
145
|
if (filepaths.includes(filepathTs)) {
|
|
@@ -167,7 +175,7 @@ function getProperties(filepath, caseStyle) {
|
|
|
167
175
|
return defaultCamelize(filepath, caseStyle);
|
|
168
176
|
}
|
|
169
177
|
async function getExports(fullpath, options, pathName) {
|
|
170
|
-
let exports = await
|
|
178
|
+
let exports = await options.loaderFS.loadFile(fullpath);
|
|
171
179
|
if (options.initializer) {
|
|
172
180
|
exports = options.initializer(exports, {
|
|
173
181
|
path: fullpath,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ManifestStore } from "./manifest.js";
|
|
2
|
+
import { Stats } from "node:fs";
|
|
3
|
+
import { LoaderFS as LoaderFS$1, LoaderFSGlobOptions } from "@eggjs/loader-fs";
|
|
4
|
+
|
|
5
|
+
//#region src/loader/loader_fs.d.ts
|
|
6
|
+
declare class ManifestLoaderFS implements LoaderFS$1 {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(manifest: ManifestStore, fallback?: LoaderFS$1);
|
|
9
|
+
exists(filepath: string): boolean;
|
|
10
|
+
stat(filepath: string): Stats;
|
|
11
|
+
realpath(filepath: string): string;
|
|
12
|
+
readJSON<T = unknown>(filepath: string): T;
|
|
13
|
+
glob(patterns: string | string[], options?: LoaderFSGlobOptions): string[];
|
|
14
|
+
loadFile(filepath: string): Promise<unknown>;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { type LoaderFS$1 as LoaderFS, ManifestLoaderFS };
|