Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
9824fbd
feat(core): add module plugin core mechanism
gxkl Jul 4, 2026
28fd1a8
feat(standalone): two-phase StandaloneApp with module plugin support
gxkl Jul 4, 2026
0297ba2
feat(tegg-plugin): instantiate InnerObjectLoadUnit in app mode
gxkl Jul 4, 2026
32c9e98
feat(tegg): convert built-in framework hooks to module plugins
gxkl Jul 4, 2026
ec04a77
docs(wiki): record tegg module plugin architecture
gxkl Jul 4, 2026
4db8a71
refactor(tegg): address module-plugin review - dedupe hook, untangle …
gxkl Jul 5, 2026
5ce2924
refactor(tegg): built-in framework hooks load through the module scan
gxkl Jul 5, 2026
3450a26
refactor(tegg): decentralize module plugins - enabling the plugin IS …
gxkl Jul 5, 2026
9f5151a
refactor(tegg): the aop PLUGIN is the aop module; provided objects jo…
gxkl Jul 5, 2026
59a0ce2
refactor(runtime): provided inner objects are ordinary protos end to end
gxkl Jul 5, 2026
8f43888
chore(aop-runtime): drop leftover InnerObjects re-export
gxkl Jul 5, 2026
11719ed
refactor(tegg): discovery stays deps/module.json-declared; drop enabl…
gxkl Jul 5, 2026
08e66c1
refactor(runtime): name the provided-instance factory for what it is
gxkl Jul 5, 2026
9e8c992
docs(aop): explain why AopContextHook stays imperatively registered
gxkl Jul 5, 2026
6be3dc1
docs(tegg): explain why inner objects use provided instances, not egg…
gxkl Jul 5, 2026
b47dd83
docs(tegg): state why ConfigSourceLoadUnitHook is a host built-in
gxkl Jul 5, 2026
f5c919a
refactor(tegg): ConfigSourceLoadUnitHook lives in @eggjs/tegg-config,…
gxkl Jul 5, 2026
d039632
fix(tegg): gate optional modules' hooks; fix the enabled-promotion match
gxkl Jul 5, 2026
a5a1bb7
revert(tegg-config): framework discovery reads package.json only
gxkl Jul 5, 2026
faddefd
refactor(standalone): defer module scan out of the StandaloneApp cons…
gxkl Jul 5, 2026
774a543
refactor(standalone): drop deprecated StandaloneAppOptions.innerObjects
gxkl Jul 5, 2026
0d5faa3
refactor(standalone): keep innerObjects assembly in the constructor, …
gxkl Jul 5, 2026
74f4ce0
refactor(standalone): make runtimeConfig a placeholder filled at init
gxkl Jul 5, 2026
0cda175
feat(standalone): accept a logger via StandaloneAppOptions
gxkl Jul 5, 2026
488006b
refactor(standalone): make StandaloneApp.init idempotent
gxkl Jul 5, 2026
118510a
fix(standalone): keep host moduleConfig handler override semantics
gxkl Jul 5, 2026
c7c4f1f
refactor(standalone): build framework base inner objects at the point…
gxkl Jul 5, 2026
4d7cb82
refactor(standalone): align StandaloneApp API with tegg#325
gxkl Jul 5, 2026
589f4fe
refactor(standalone): discover builtin framework plugins via own pack…
gxkl Jul 5, 2026
3c51287
refactor(standalone): move dal manager cleanup into the dal module it…
gxkl Jul 5, 2026
a86b5f2
feat(dal): declare the mysqlDataSourceManager injection surface in th…
gxkl Jul 5, 2026
ea724e6
fix(dal): declare manager cleanup via @LifecycleDestroy
gxkl Jul 5, 2026
1c63005
refactor(dal): type MysqlDataSourceManagerObject via declaration merging
gxkl Jul 5, 2026
d7b9ede
fix(standalone): allowlist scan-declaration deps for unplugin-unused
gxkl Jul 5, 2026
ab57cc9
fix(core-decorator): explicit return types for isolatedDeclarations
gxkl Jul 5, 2026
0140cc8
fix(config): default the framework module scan to egg
gxkl Jul 5, 2026
cb3d29c
refactor(config): resolve the framework dir with getFrameworkPath
gxkl Jul 5, 2026
32f326b
fix(config): tolerate non-materialized module dirs from bundle manifests
gxkl Jul 5, 2026
796d279
fix(tegg): JSON-safe descriptor dump and bundle-tolerant module confi…
gxkl Jul 5, 2026
46326b1
test(tegg): explicit boot-hook timeouts for slow Windows runners
gxkl Jul 5, 2026
fd2161a
test(tegg): align boot-hook timeouts with the root config values
gxkl Jul 5, 2026
832dd03
fix(loader): remove redundant test glob excludes
gxkl Jul 9, 2026
29290e4
chore(tegg-config): debug framework resolution failures
gxkl Jul 9, 2026
f63888a
chore(tegg): remove empty plugin boot hooks
gxkl Jul 9, 2026
24364ee
fix(metadata): emit valid module descriptor JSON
gxkl Jul 9, 2026
df9aadf
fix(standalone): pass framework deps during preload
gxkl Jul 9, 2026
9282e2e
fix(standalone): await app destroy on success
gxkl Jul 9, 2026
f97739f
fix(standalone): reject removed innerObjects option
gxkl Jul 9, 2026
d82f600
docs(tegg): correct module plugin feeding rules
gxkl Jul 9, 2026
4ccd29f
fix(standalone): reuse manifest module references
gxkl Jul 9, 2026
01407c0
fix(standalone): let provided inner objects override defaults
gxkl Jul 9, 2026
8abee4b
fix(tegg): narrow lifecycle proto types
gxkl Jul 9, 2026
e61ce22
fix(tegg): clean partial module init failures
gxkl Jul 9, 2026
771f6f1
refactor(tegg): share tolerant module config resolution
gxkl Jul 9, 2026
b16bfab
test(tegg): cover inner object multi-app isolation
gxkl Jul 9, 2026
b9dd087
fix(tegg): match module plugins by package
gxkl Jul 9, 2026
17b5314
refactor(tegg): share manifest data builder
gxkl Jul 9, 2026
92c8c53
fix(tegg-config): scan parent framework modules
gxkl Jul 9, 2026
fad791b
fix(tegg): qualify inner objects by defining module
gxkl Jul 9, 2026
7773876
refactor(aop): register context hook as inner object
gxkl Jul 9, 2026
a316936
refactor(dal): inject mysql data source manager
gxkl Jul 9, 2026
0ca40eb
refactor(metadata): reuse prototype builder for inner objects
gxkl Jul 9, 2026
17f4819
test(standalone): expect destroy lifecycle after main
gxkl Jul 9, 2026
1132499
fix(tegg-config): keep nearest duplicate framework modules
gxkl Jul 9, 2026
294c78e
fix(tegg-config): stop at boolean framework roots
gxkl Jul 9, 2026
10c6e62
fix(standalone): clarify inner object override warnings
gxkl Jul 9, 2026
9c26cfd
test(tegg-config): cover framework module dedupe edges
gxkl Jul 9, 2026
ac38700
refactor(dal): inject table and sql map managers
gxkl Jul 9, 2026
eba836b
fix(tegg-config): resolve framework module json packages locally
gxkl Jul 9, 2026
c356ead
docs(standalone): update inner object handler option
gxkl Jul 9, 2026
5c42a6d
fix(tegg): address review follow-ups
gxkl Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tegg/core/aop-decorator/src/CrosscutAdviceFactory.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import assert from 'node:assert';

import { InnerObjectProto } from '@eggjs/core-decorator';
import type { EggProtoImplClass, IAdvice, AdviceInfo } from '@eggjs/tegg-types';

import { CrosscutInfoUtil } from './util/index.ts';

@InnerObjectProto()
export class CrosscutAdviceFactory {
private readonly crosscutAdviceClazzList: Array<EggProtoImplClass<IAdvice>> = [];

Expand Down
4 changes: 1 addition & 3 deletions tegg/core/aop-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"dependencies": {
"@eggjs/aop-decorator": "workspace:*",
"@eggjs/core-decorator": "workspace:*",
"@eggjs/lifecycle": "workspace:*",
"@eggjs/metadata": "workspace:*",
"@eggjs/tegg-common-util": "workspace:*",
"@eggjs/tegg-runtime": "workspace:*",
Expand All @@ -59,8 +60,5 @@
},
"engines": {
"node": ">=22.18.0"
},
"eggModule": {
"name": "teggAopRuntime"
}
}
27 changes: 27 additions & 0 deletions tegg/core/aop-runtime/src/AopContextAdviceRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { InnerObjectProto } from '@eggjs/core-decorator';
import { ObjectInitType } from '@eggjs/tegg-types';
import type { EggPrototype } from '@eggjs/tegg-types';

export interface ProtoToCreate {
name: string;
proto: EggPrototype;
}

@InnerObjectProto()
Comment thread
coderabbitai[bot] marked this conversation as resolved.
export class AopContextAdviceRegistry {
readonly #requestProtoList: ProtoToCreate[] = [];

addAdvice(name: string, proto: EggPrototype): void {
if (proto.initType !== ObjectInitType.CONTEXT) {
return;
}
if (this.#requestProtoList.some((t) => t.name === name && t.proto === proto)) {
return;
}
this.#requestProtoList.push({ name, proto });
}

getRequestProtos(): readonly ProtoToCreate[] {
return this.#requestProtoList;
}
}
27 changes: 27 additions & 0 deletions tegg/core/aop-runtime/src/AopGraphHookRegistrar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { InnerObjectProto } from '@eggjs/core-decorator';
import { LifecyclePostInject } from '@eggjs/lifecycle';
import { GlobalGraph } from '@eggjs/metadata';

import { crossCutGraphHook } from './CrossCutGraphHook.js';
import { pointCutGraphHook } from './PointCutGraphHook.js';
Comment on lines +5 to +6

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the repository's general rules, TypeScript source file imports should use the .ts extension instead of .js to maintain consistency across the codebase.

Suggested change
import { crossCutGraphHook } from './CrossCutGraphHook.js';
import { pointCutGraphHook } from './PointCutGraphHook.js';
import { crossCutGraphHook } from './CrossCutGraphHook.ts';
import { pointCutGraphHook } from './PointCutGraphHook.ts';
References
  1. In this repository, use '.ts' extensions in import/export paths for TypeScript source files to maintain consistency with the existing convention across source and test files.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不采纳这里的 .ts import 建议。tegg 源码当前按 ESM 输出规范使用 .js import specifier,同包其它 TS 源码也是这个模式;改成 .ts 反而会和现有构建/类型检查约定不一致。


/**
* Registers the AOP graph build hooks declaratively. Instantiated with the
* InnerObjectLoadUnit, which both hosts run AFTER the business GlobalGraph is
* created and BEFORE build() consumes the hooks — the only valid window.
*/
@InnerObjectProto()
export class AopGraphHookRegistrar {
@LifecyclePostInject()
protected registerGraphHooks(): void {
const globalGraph = GlobalGraph.instance;
if (!globalGraph) {
throw new Error(
'[aop-runtime] GlobalGraph must be created before AopGraphHookRegistrar is instantiated, ' +
'cross-loadUnit crosscut/pointcut weaving would silently never happen',
);
}
globalGraph.registerBuildHook(crossCutGraphHook);
globalGraph.registerBuildHook(pointCutGraphHook);
}
}
3 changes: 2 additions & 1 deletion tegg/core/aop-runtime/src/EggObjectAopHook.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import assert from 'node:assert';

import { Aspect } from '@eggjs/aop-decorator';
import { PrototypeUtil } from '@eggjs/core-decorator';
import { EggObjectLifecycleProto, PrototypeUtil } from '@eggjs/core-decorator';
import { EggContainerFactory } from '@eggjs/tegg-runtime';
import { ASPECT_LIST, InjectType } from '@eggjs/tegg-types';
import type { EggObject, EggObjectLifeCycleContext, LifecycleHook } from '@eggjs/tegg-types';

import { AspectExecutor } from './AspectExecutor.js';

@EggObjectLifecycleProto()
export class EggObjectAopHook implements LifecycleHook<EggObjectLifeCycleContext, EggObject> {
private hijackMethods(obj: any, aspectList: Array<Aspect>) {
for (const aspect of aspectList) {
Expand Down
7 changes: 3 additions & 4 deletions tegg/core/aop-runtime/src/EggPrototypeCrossCutHook.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { CrosscutAdviceFactory, CrosscutInfoUtil } from '@eggjs/aop-decorator';
import { EggPrototypeLifecycleProto, Inject } from '@eggjs/core-decorator';
import type { EggPrototype, EggPrototypeLifecycleContext, LifecycleHook } from '@eggjs/tegg-types';

@EggPrototypeLifecycleProto()
export class EggPrototypeCrossCutHook implements LifecycleHook<EggPrototypeLifecycleContext, EggPrototype> {
@Inject()
private readonly crosscutAdviceFactory: CrosscutAdviceFactory;

constructor(crosscutAdviceFactory: CrosscutAdviceFactory) {
this.crosscutAdviceFactory = crosscutAdviceFactory;
}

async preCreate(ctx: EggPrototypeLifecycleContext): Promise<void> {
if (CrosscutInfoUtil.isCrosscutAdvice(ctx.clazz)) {
this.crosscutAdviceFactory.registerCrossAdviceClazz(ctx.clazz);
Expand Down
11 changes: 8 additions & 3 deletions tegg/core/aop-runtime/src/LoadUnitAopHook.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AspectInfoUtil, AspectMetaBuilder, CrosscutAdviceFactory } from '@eggjs/aop-decorator';
import { Inject, LoadUnitLifecycleProto } from '@eggjs/core-decorator';
import { EggPrototypeFactory, TeggError } from '@eggjs/metadata';
import type {
EggPrototype,
Expand All @@ -8,12 +9,15 @@ import type {
LoadUnitLifecycleContext,
} from '@eggjs/tegg-types';

import { AopContextAdviceRegistry } from './AopContextAdviceRegistry.js';

@LoadUnitLifecycleProto()
export class LoadUnitAopHook implements LifecycleHook<LoadUnitLifecycleContext, LoadUnit> {
@Inject()
private readonly crosscutAdviceFactory: CrosscutAdviceFactory;

constructor(crosscutAdviceFactory: CrosscutAdviceFactory) {
this.crosscutAdviceFactory = crosscutAdviceFactory;
}
@Inject()
private readonly aopContextAdviceRegistry: AopContextAdviceRegistry;

async postCreate(_: LoadUnitLifecycleContext, loadUnit: LoadUnit): Promise<void> {
for (const proto of loadUnit.iterateEggPrototype()) {
Expand All @@ -39,6 +43,7 @@ export class LoadUnitAopHook implements LifecycleHook<LoadUnitLifecycleContext,
qualifiers: [],
proto: adviceProto as EggPrototype,
});
this.aopContextAdviceRegistry.addAdvice(advice.name, adviceProto as EggPrototype);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions tegg/core/aop-runtime/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export * from './AopContextAdviceRegistry.js';
export * from './AspectExecutor.js';
export * from './CrossCutGraphHook.js';
export * from './EggObjectAopHook.js';
export * from './EggPrototypeCrossCutHook.js';
export * from './LoadUnitAopHook.js';
export * from './PointCutGraphHook.js';
export * from './AopGraphHookRegistrar.js';
2 changes: 2 additions & 0 deletions tegg/core/aop-runtime/test/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

exports[`should export stable 1`] = `
{
"AopContextAdviceRegistry": [Function],
"AopGraphHookRegistrar": [Function],
"AspectExecutor": [Function],
"EggObjectAopHook": [Function],
"EggPrototypeCrossCutHook": [Function],
Expand Down
26 changes: 17 additions & 9 deletions tegg/core/aop-runtime/test/aop-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { describe, beforeEach, afterEach, it } from 'vitest';
import { Hello } from './fixtures/modules/hello_succeed/Hello.js';

import { crossCutGraphHook } from '../src/CrossCutGraphHook.js';
import { AopContextAdviceRegistry } from '../src/AopContextAdviceRegistry.js';
import { EggObjectAopHook } from '../src/EggObjectAopHook.js';
import { EggPrototypeCrossCutHook } from '../src/EggPrototypeCrossCutHook.js';
import { LoadUnitAopHook } from '../src/LoadUnitAopHook.js';
Expand All @@ -22,6 +23,13 @@ import { CallTrace } from './fixtures/modules/hello_cross_cut/CallTrace.js';
import { crosscutAdviceParams } from './fixtures/modules/hello_cross_cut/HelloCrossCut.js';
import { pointcutAdviceParams } from './fixtures/modules/hello_point_cut/HelloPointCut.js';

function createLoadUnitAopHook(crosscutAdviceFactory: CrosscutAdviceFactory): LoadUnitAopHook {
const loadUnitAopHook = new LoadUnitAopHook();
Reflect.set(loadUnitAopHook, 'crosscutAdviceFactory', crosscutAdviceFactory);
Reflect.set(loadUnitAopHook, 'aopContextAdviceRegistry', new AopContextAdviceRegistry());
return loadUnitAopHook;
}

describe('test/aop-runtime.test.ts', () => {
afterEach(() => {
mock.reset();
Expand All @@ -37,15 +45,15 @@ describe('test/aop-runtime.test.ts', () => {
beforeEach(async () => {
crosscutAdviceFactory = new CrosscutAdviceFactory();
eggObjectAopHook = new EggObjectAopHook();
loadUnitAopHook = new LoadUnitAopHook(crosscutAdviceFactory);
eggPrototypeCrossCutHook = new EggPrototypeCrossCutHook(crosscutAdviceFactory);
loadUnitAopHook = createLoadUnitAopHook(crosscutAdviceFactory);
eggPrototypeCrossCutHook = new EggPrototypeCrossCutHook();
Reflect.set(eggPrototypeCrossCutHook, 'crosscutAdviceFactory', crosscutAdviceFactory);
EggPrototypeLifecycleUtil.registerLifecycle(eggPrototypeCrossCutHook);
LoadUnitLifecycleUtil.registerLifecycle(loadUnitAopHook);
EggObjectLifecycleUtil.registerLifecycle(eggObjectAopHook);

modules = await CoreTestHelper.prepareModules(
[
path.join(__dirname, '..'),
path.join(__dirname, 'fixtures/modules/hello_succeed'),
path.join(__dirname, 'fixtures/modules/hello_point_cut'),
path.join(__dirname, 'fixtures/modules/state_point_cut'),
Expand Down Expand Up @@ -166,8 +174,9 @@ describe('test/aop-runtime.test.ts', () => {
beforeEach(async () => {
crosscutAdviceFactory = new CrosscutAdviceFactory();
eggObjectAopHook = new EggObjectAopHook();
loadUnitAopHook = new LoadUnitAopHook(crosscutAdviceFactory);
eggPrototypeCrossCutHook = new EggPrototypeCrossCutHook(crosscutAdviceFactory);
loadUnitAopHook = createLoadUnitAopHook(crosscutAdviceFactory);
eggPrototypeCrossCutHook = new EggPrototypeCrossCutHook();
Reflect.set(eggPrototypeCrossCutHook, 'crosscutAdviceFactory', crosscutAdviceFactory);
EggPrototypeLifecycleUtil.registerLifecycle(eggPrototypeCrossCutHook);
LoadUnitLifecycleUtil.registerLifecycle(loadUnitAopHook);
EggObjectLifecycleUtil.registerLifecycle(eggObjectAopHook);
Expand All @@ -176,7 +185,6 @@ describe('test/aop-runtime.test.ts', () => {
it('should throw', async () => {
await assert.rejects(async () => {
await CoreTestHelper.prepareModules([
path.join(__dirname, '..'),
path.join(__dirname, 'fixtures/modules/should_throw'),
]);
}, /Aop Advice\(PointcutAdvice\) not found in loadUnits/);
Expand All @@ -193,15 +201,15 @@ describe('test/aop-runtime.test.ts', () => {
beforeEach(async () => {
crosscutAdviceFactory = new CrosscutAdviceFactory();
eggObjectAopHook = new EggObjectAopHook();
loadUnitAopHook = new LoadUnitAopHook(crosscutAdviceFactory);
eggPrototypeCrossCutHook = new EggPrototypeCrossCutHook(crosscutAdviceFactory);
loadUnitAopHook = createLoadUnitAopHook(crosscutAdviceFactory);
eggPrototypeCrossCutHook = new EggPrototypeCrossCutHook();
Reflect.set(eggPrototypeCrossCutHook, 'crosscutAdviceFactory', crosscutAdviceFactory);
EggPrototypeLifecycleUtil.registerLifecycle(eggPrototypeCrossCutHook);
LoadUnitLifecycleUtil.registerLifecycle(loadUnitAopHook);
EggObjectLifecycleUtil.registerLifecycle(eggObjectAopHook);

modules = await CoreTestHelper.prepareModules(
[
path.join(__dirname, '..'),
path.join(__dirname, 'fixtures/modules/constructor_inject_aop'),
path.join(__dirname, 'fixtures/modules/hello_point_cut'),
path.join(__dirname, 'fixtures/modules/hello_cross_cut'),
Expand Down
69 changes: 58 additions & 11 deletions tegg/core/common-util/src/ModuleConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ const DEFAULT_READ_MODULE_REF_OPTS = {

const CONFIG_NAMES_SLOT = Symbol('tegg:common-util:moduleConfigNames');

export interface ResolvedModuleConfig {
name: string;
path: string;
config: ModuleConfig;
}

export class ModuleConfigUtil {
// Per-app/per-Runner: each standalone Runner (and app) has distinct config
// names (env-based); a process-global static races across them (the standalone
Expand Down Expand Up @@ -80,15 +86,21 @@ export class ModuleConfigUtil {
const pkgJson = path.posix.join(moduleReferenceConfig.package, 'package.json');
const file = importResolve(pkgJson, options);
const modulePath = path.dirname(file);
const pkg = ModuleConfigUtil.readPackageJsonSync(modulePath);
moduleReference = {
path: modulePath,
name: ModuleConfigUtil.readModuleNameSync(modulePath),
name: ModuleConfigUtil.getModuleName(pkg),
package: ModuleConfigUtil.getPackageName(pkg),
...(moduleReferenceConfig.optional === undefined ? {} : { optional: moduleReferenceConfig.optional }),
};
} else if (ModuleReferenceConfigHelp.isInlineModuleReference(moduleReferenceConfig)) {
const modulePath = path.join(configDir, moduleReferenceConfig.path);
const pkg = ModuleConfigUtil.readPackageJsonSync(modulePath);
moduleReference = {
path: modulePath,
name: ModuleConfigUtil.readModuleNameSync(modulePath),
name: ModuleConfigUtil.getModuleName(pkg),
package: ModuleConfigUtil.getPackageName(pkg),
...(moduleReferenceConfig.optional === undefined ? {} : { optional: moduleReferenceConfig.optional }),
};
} else {
throw new Error('unknown type of module reference config: ' + JSON.stringify(moduleReferenceConfig));
Expand Down Expand Up @@ -138,15 +150,18 @@ export class ModuleConfigUtil {
}
moduleDirSet.add(moduleDir);

let pkg: any;
let name: string;
try {
name = this.readModuleNameSync(moduleDir);
pkg = this.readPackageJsonSync(moduleDir);
name = this.getModuleName(pkg);
} catch {
continue;
}
ref.push({
path: moduleDir,
name,
package: this.getPackageName(pkg),
});
}
const moduleReferences = this.readModuleFromNodeModules(baseDir);
Expand All @@ -157,10 +172,7 @@ export class ModuleConfigUtil {
throw new Error('duplicate import of module reference: ' + moduleBasePath);
}
});
ref.push({
path: moduleReference.path,
name: moduleReference.name,
});
ref.push(moduleReference);
}
return ref;
}
Expand Down Expand Up @@ -188,10 +200,11 @@ export class ModuleConfigUtil {
const absolutePkgPath = path.dirname(packageJsonPath);
const realPkgPath = fs.realpathSync(absolutePkgPath);
try {
const name = this.readModuleNameSync(realPkgPath);
const pkg = this.readPackageJsonSync(realPkgPath);
ref.push({
path: realPkgPath,
name,
name: this.getModuleName(pkg),
package: this.getPackageName(pkg),
});
} catch {
continue;
Expand All @@ -213,6 +226,15 @@ export class ModuleConfigUtil {
return pkg.eggModule.name;
}

private static getPackageName(pkg: any): string | undefined {
return pkg.name;
}

private static readPackageJsonSync(moduleDir: string): any {
const pkgContent = fs.readFileSync(path.join(moduleDir, 'package.json'), 'utf8');
return JSON.parse(pkgContent);
}

public static async readModuleName(baseDir: string, moduleDir: string): Promise<string> {
moduleDir = ModuleConfigUtil.resolveModuleDir(moduleDir, baseDir);
const pkgContent = await fsPromise.readFile(path.join(moduleDir, 'package.json'), 'utf8');
Expand All @@ -222,8 +244,7 @@ export class ModuleConfigUtil {

public static readModuleNameSync(moduleDir: string, baseDir?: string): string {
moduleDir = ModuleConfigUtil.resolveModuleDir(moduleDir, baseDir);
const pkgContent = fs.readFileSync(path.join(moduleDir, 'package.json'), 'utf8');
const pkg = JSON.parse(pkgContent);
const pkg = ModuleConfigUtil.readPackageJsonSync(moduleDir);
return ModuleConfigUtil.getModuleName(pkg);
}

Expand Down Expand Up @@ -306,6 +327,32 @@ export class ModuleConfigUtil {
return target;
}

public static resolveModuleConfigTolerant(
reference: ModuleReference,
baseDir?: string,
env?: string,
): ResolvedModuleConfig {
if (!path.isAbsolute(reference.path)) {
assert(baseDir, 'baseDir is required for relative module reference path');
}
const modulePath = path.isAbsolute(reference.path) ? reference.path : path.resolve(baseDir!, reference.path);

if (!fs.existsSync(modulePath) && reference.name) {
return {
name: reference.name,
path: modulePath,
config: {},
};
}

const name = ModuleConfigUtil.readModuleNameSync(modulePath);
return {
name,
path: modulePath,
config: ModuleConfigUtil.loadModuleConfigSync(modulePath, undefined, env),
};
}

static #loadOneSync(moduleDir: string, configName: string): ModuleConfig | undefined {
const yamlConfigPath = path.join(moduleDir, `${configName}.yml`);
let config = ModuleConfigUtil.#loadYamlSync(yamlConfigPath);
Expand Down
Loading
Loading