@eggjs/core 7.0.2-beta.2 → 7.0.2-beta.22

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.
@@ -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 { exists, getParamNames, readJSON, readJSONSync } from "utility";
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 = readJSONSync(path.join(this.options.baseDir, "package.json"));
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 (await utils_default.existsPath(pluginPackage)) {
386
- pkg = await readJSON(pluginPackage);
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,60 @@ 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 (this.#isBundleModeForThisApp() && (!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
+ /**
496
+ * Whether an active bundle store belongs to THIS app. The store is shared via globalThis
497
+ * across @eggjs/core copies, so one registered for a different app must not reinterpret this
498
+ * app's plugin paths — mirror `ManifestStore.load()`'s `bundleStore.baseDir === baseDir` gate.
499
+ */
500
+ #isBundleModeForThisApp() {
501
+ const bundleStore = ManifestStore.getBundleStore();
502
+ return !!bundleStore && path.resolve(bundleStore.baseDir) === path.resolve(this.options.baseDir);
503
+ }
504
+ #isBundlePluginPathArtifact(pluginPath) {
505
+ if (!this.#isBundleModeForThisApp()) return false;
506
+ return path.resolve(pluginPath) === path.resolve(this.options.baseDir);
507
+ }
508
+ /**
509
+ * Re-resolve a bundle-artifact plugin path to the directory of the plugin package's entry
510
+ * module — the same directory `definePluginFactory` captured via `import.meta.dirname` at
511
+ * build time. Built-in framework plugins only carry a `name` (no `package`), so fall back to
512
+ * the conventional `@eggjs/<name>` package name in addition to the bare name.
513
+ */
514
+ #resolveBundlePluginPath(plugin) {
515
+ const candidates = plugin.package ? [plugin.package] : plugin.name.includes("/") ? [plugin.name] : [plugin.name, `@eggjs/${plugin.name}`];
516
+ let lastErr;
517
+ for (const name$1 of candidates) try {
518
+ let realDir;
519
+ try {
520
+ realDir = path.dirname(utils_default.resolvePath(name$1, { paths: [...this.lookupDirs] }));
521
+ } catch {
522
+ realDir = path.dirname(utils_default.resolvePath(`${name$1}/package.json`, { paths: [...this.lookupDirs] }));
523
+ }
524
+ const segments = realDir.split(/[/\\]/);
525
+ const nmIdx = segments.lastIndexOf("node_modules");
526
+ if (nmIdx !== -1) {
527
+ const rebased = path.join(this.options.baseDir, ...segments.slice(nmIdx));
528
+ if (fs.existsSync(rebased)) return rebased;
529
+ }
530
+ return realDir;
531
+ } catch (err) {
532
+ lastErr = err;
533
+ }
534
+ const name = plugin.package || plugin.name;
535
+ debug("[resolveBundlePluginPath] error: %o, plugin info: %o", lastErr, plugin);
536
+ throw new Error(`Can not find plugin ${name} in "${[...this.lookupDirs].join(", ")}"`, { cause: lastErr });
537
+ }
462
538
  #resolvePluginPath(plugin) {
463
539
  const name = plugin.package || plugin.name;
464
540
  try {
@@ -476,7 +552,7 @@ var EggLoader = class {
476
552
  if (isESM) {
477
553
  if (exports.import) realPluginPath = path.join(pluginPath, exports.import);
478
554
  } else if (exports.require) realPluginPath = path.join(pluginPath, exports.require);
479
- if (exports.typescript && isSupportTypeScript() && !await exists(realPluginPath)) {
555
+ if (exports.typescript && isSupportTypeScript() && !this.loaderFS.exists(realPluginPath)) {
480
556
  realPluginPath = path.join(pluginPath, exports.typescript);
481
557
  debug("[formatPluginPathFromPackageJSON] use typescript path %o", realPluginPath);
482
558
  }
@@ -742,14 +818,16 @@ var EggLoader = class {
742
818
  */
743
819
  async loadCustomApp() {
744
820
  await this.#loadBootHook("app");
745
- this.lifecycle.triggerConfigWillLoad();
821
+ if (this.options.metadataOnly) await this.lifecycle.triggerLoadMetadata();
822
+ else this.lifecycle.triggerConfigWillLoad();
746
823
  }
747
824
  /**
748
825
  * Load agent.js, same as {@link EggLoader#loadCustomApp}
749
826
  */
750
827
  async loadCustomAgent() {
751
828
  await this.#loadBootHook("agent");
752
- this.lifecycle.triggerConfigWillLoad();
829
+ if (this.options.metadataOnly) await this.lifecycle.triggerLoadMetadata();
830
+ else this.lifecycle.triggerConfigWillLoad();
753
831
  }
754
832
  loadBootHook() {}
755
833
  async #loadBootHook(fileName) {
@@ -1042,7 +1120,9 @@ var EggLoader = class {
1042
1120
  ...options,
1043
1121
  directory: options?.directory ?? directory,
1044
1122
  target,
1045
- inject: this.app
1123
+ inject: this.app,
1124
+ manifest: this.manifest,
1125
+ loaderFS: options?.loaderFS ?? this.loaderFS
1046
1126
  };
1047
1127
  const timingKey = `Load "${String(property)}" to Application`;
1048
1128
  this.timing.start(timingKey);
@@ -1061,7 +1141,9 @@ var EggLoader = class {
1061
1141
  ...options,
1062
1142
  directory: options?.directory || directory,
1063
1143
  property,
1064
- inject: this.app
1144
+ inject: this.app,
1145
+ manifest: this.manifest,
1146
+ loaderFS: options?.loaderFS ?? this.loaderFS
1065
1147
  };
1066
1148
  const timingKey = `Load "${String(property)}" to Context`;
1067
1149
  this.timing.start(timingKey);
@@ -1091,14 +1173,110 @@ var EggLoader = class {
1091
1173
  return files;
1092
1174
  }
1093
1175
  resolveModule(filepath) {
1176
+ return this.manifest.resolveModule(filepath, () => this.#doResolveModule(filepath));
1177
+ }
1178
+ #doResolveModule(filepath) {
1094
1179
  let fullPath;
1095
1180
  try {
1096
1181
  fullPath = utils_default.resolvePath(filepath);
1097
- } catch {
1098
- return;
1099
- }
1182
+ } catch {}
1183
+ if (!fullPath) fullPath = this.#resolveFromOutDir(filepath);
1100
1184
  return fullPath;
1101
1185
  }
1186
+ #resolveOutDir() {
1187
+ if (this.pkg.egg?.outDir) {
1188
+ debug("[resolveOutDir] use pkg.egg.outDir: %o", this.pkg.egg.outDir);
1189
+ return this.pkg.egg.outDir;
1190
+ }
1191
+ const tsConfigFile = path.join(this.options.baseDir, "tsconfig.json");
1192
+ if (fs.existsSync(tsConfigFile)) try {
1193
+ const tsConfig = JSON.parse(fs.readFileSync(tsConfigFile, "utf-8"));
1194
+ if (tsConfig.compilerOptions?.outDir) {
1195
+ debug("[resolveOutDir] use tsconfig.json compilerOptions.outDir: %o", tsConfig.compilerOptions.outDir);
1196
+ return tsConfig.compilerOptions.outDir;
1197
+ }
1198
+ } catch {}
1199
+ }
1200
+ #resolveFromOutDir(filepath) {
1201
+ if (!this.outDir) return;
1202
+ const baseDir = this.options.baseDir;
1203
+ if (!filepath.startsWith(baseDir + path.sep)) return;
1204
+ const relativePath = path.relative(baseDir, filepath);
1205
+ for (const ext of [".js", ".mjs"]) {
1206
+ const outDirPath = path.join(baseDir, this.outDir, relativePath + ext);
1207
+ if (fs.existsSync(outDirPath)) {
1208
+ debug("[resolveModule:outDir] %o => %o", filepath, outDirPath);
1209
+ return outDirPath;
1210
+ }
1211
+ }
1212
+ }
1213
+ /**
1214
+ * Generate startup manifest from collected data.
1215
+ * Should be called after all loading phases complete.
1216
+ */
1217
+ generateManifest() {
1218
+ const manifest = this.manifest.generateManifest({
1219
+ serverEnv: this.serverEnv,
1220
+ serverScope: this.serverScope,
1221
+ typescriptEnabled: isSupportTypeScript()
1222
+ });
1223
+ this.#collectConventionalDynamicFiles(manifest);
1224
+ return manifest;
1225
+ }
1226
+ /**
1227
+ * metadataOnly startup intentionally skips the agent process, but bundled
1228
+ * single-mode workers still load agent boot hooks and agent extends later.
1229
+ * Record convention-based dynamic entry points so the bundle can satisfy
1230
+ * those runtime lookups without running agent lifecycle hooks at manifest
1231
+ * generation time.
1232
+ */
1233
+ #collectConventionalDynamicFiles(manifest) {
1234
+ const resolveCacheTargets = new Set(Object.values(manifest.resolveCache).filter((target) => typeof target === "string"));
1235
+ for (const unit of this.getLoadUnits()) {
1236
+ this.#collectConventionFile(manifest, path.join(unit.path, "package.json"), resolveCacheTargets);
1237
+ for (const load of CONVENTIONAL_MANIFEST_LOADS) {
1238
+ const target = path.join(unit.path, ...load.path);
1239
+ if (load.type === "resolve") this.#collectConventionResolve(manifest, target, resolveCacheTargets);
1240
+ else if ("extensionlessResolve" in load && load.extensionlessResolve) this.#collectConventionFileResolves(manifest, target, resolveCacheTargets);
1241
+ else this.#collectConventionFileDiscovery(manifest, target);
1242
+ }
1243
+ }
1244
+ }
1245
+ #collectConventionResolve(manifest, request, resolveCacheTargets) {
1246
+ const requestKey = this.#toManifestRel(request);
1247
+ if (Object.hasOwn(manifest.resolveCache, requestKey)) return;
1248
+ const resolved = this.#doResolveModule(request);
1249
+ const resolvedKey = resolved ? this.#toManifestRel(resolved) : null;
1250
+ manifest.resolveCache[requestKey] = resolvedKey;
1251
+ if (resolvedKey !== null) resolveCacheTargets.add(resolvedKey);
1252
+ }
1253
+ #collectConventionFileResolves(manifest, directory, resolveCacheTargets) {
1254
+ const files = this.#collectConventionFileDiscovery(manifest, directory);
1255
+ for (const file of files) {
1256
+ const ext = path.extname(file);
1257
+ if (!ext) continue;
1258
+ const request = path.join(directory, file.slice(0, -ext.length));
1259
+ this.#collectConventionResolve(manifest, request, resolveCacheTargets);
1260
+ }
1261
+ }
1262
+ #collectConventionFileDiscovery(manifest, directory) {
1263
+ const dirKey = this.#toManifestRel(directory);
1264
+ if (Object.hasOwn(manifest.fileDiscovery, dirKey)) return manifest.fileDiscovery[dirKey];
1265
+ manifest.fileDiscovery[dirKey] = fs.existsSync(directory) && fs.statSync(directory).isDirectory() ? globby.sync(FileLoader.getDefaultMatch(), { cwd: directory }).sort() : [];
1266
+ return manifest.fileDiscovery[dirKey];
1267
+ }
1268
+ #collectConventionFile(manifest, filepath, resolveCacheTargets) {
1269
+ const fileKey = this.#toManifestRel(filepath);
1270
+ if (resolveCacheTargets.has(fileKey)) return;
1271
+ if (!fs.existsSync(filepath) || !fs.statSync(filepath).isFile()) return;
1272
+ const dirKey = this.#toManifestRel(path.dirname(filepath));
1273
+ const basename = path.basename(filepath);
1274
+ const files = manifest.fileDiscovery[dirKey] ?? [];
1275
+ if (!files.includes(basename)) manifest.fileDiscovery[dirKey] = [...files, basename].sort();
1276
+ }
1277
+ #toManifestRel(filepath) {
1278
+ return (path.isAbsolute(filepath) ? path.relative(this.options.baseDir, filepath) : filepath).replaceAll(path.sep, "/");
1279
+ }
1102
1280
  };
1103
1281
  function depCompatible(plugin) {
1104
1282
  if (plugin.dep && !(Array.isArray(plugin.dependencies) && plugin.dependencies.length > 0)) {
@@ -1,4 +1,5 @@
1
- import { Fun } from "../utils/index.js";
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: object | Fun;
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
- readonly options: FileLoaderOptions & Required<Pick<FileLoaderOptions, "caseStyle">>;
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 globby from "globby";
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|mjs|cjs)", "!**/*.d.ts"] : ["**/*.{js,mjs,cjs}"];
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 = isSupportTypeScript() ? ["**/*.(js|ts)", "!**/*.d.ts"] : ["**/*.js"];
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,13 +134,14 @@ var FileLoader = class {
127
134
  const items = [];
128
135
  debug("[parse] parsing directories: %j", directories);
129
136
  for (const directory of directories) {
130
- const filepaths = globby.sync(files, { cwd: directory });
131
- debug("[parse] globby files: %o, cwd: %o => %o", files, directory, filepaths);
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 (!fs.statSync(fullpath).isFile()) continue;
135
- if (filepath.endsWith(".js")) {
136
- const filepathTs = filepath.replace(/\.js$/, ".ts");
142
+ if (!this.options.loaderFS.stat(fullpath).isFile()) continue;
143
+ if (filepath.endsWith(".js") || filepath.endsWith(".mjs") || filepath.endsWith(".cjs")) {
144
+ const filepathTs = filepath.replace(/\.(?:js|mjs|cjs)$/, ".ts");
137
145
  if (filepaths.includes(filepathTs)) {
138
146
  debug("[parse] ignore %s, because %s exists", fullpath, filepathTs);
139
147
  continue;
@@ -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 utils_default.loadFile(fullpath);
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 };