fix(core): instantiate nested transient providers in static context

This commit is contained in:
mag123c
2025-12-19 17:14:00 +09:00
parent 8d4d0443b0
commit 351f977b3d
2 changed files with 84 additions and 1 deletions

View File

@@ -417,7 +417,11 @@ export class InstanceWrapper<T = any> {
contextId === STATIC_CONTEXT &&
(!this.isTransient ||
(isStaticTransient && !!inquirer && !inquirer.isTransient) ||
(isStaticTransient && !!rootInquirer && !rootInquirer.isTransient))
(isStaticTransient && !!rootInquirer && !rootInquirer.isTransient) ||
(isStaticTransient &&
!!inquirer &&
inquirer.isTransient &&
!rootInquirer))
);
}

View File

@@ -190,4 +190,83 @@ describe('Nested Transient Isolation', () => {
);
});
});
describe('when DEFAULT scoped provider depends on nested TRANSIENT chain', () => {
@Injectable({ scope: Scope.TRANSIENT })
class NestedTransientService {
public static constructorCalled = false;
public readonly value = 'nested-initialized';
constructor() {
NestedTransientService.constructorCalled = true;
}
}
@Injectable({ scope: Scope.TRANSIENT })
class TransientService {
public static constructorCalled = false;
constructor(public readonly nested: NestedTransientService) {
TransientService.constructorCalled = true;
}
}
@Injectable()
class DefaultScopedParent {
constructor(public readonly transient: TransientService) {}
}
let nestedTransientWrapper: InstanceWrapper;
let transientWrapper: InstanceWrapper;
let parentWrapper: InstanceWrapper;
beforeEach(() => {
NestedTransientService.constructorCalled = false;
TransientService.constructorCalled = false;
nestedTransientWrapper = new InstanceWrapper({
name: NestedTransientService.name,
token: NestedTransientService,
metatype: NestedTransientService,
scope: Scope.TRANSIENT,
host: module,
});
transientWrapper = new InstanceWrapper({
name: TransientService.name,
token: TransientService,
metatype: TransientService,
scope: Scope.TRANSIENT,
host: module,
});
parentWrapper = new InstanceWrapper({
name: DefaultScopedParent.name,
token: DefaultScopedParent,
metatype: DefaultScopedParent,
scope: Scope.DEFAULT,
host: module,
});
module.providers.set(NestedTransientService, nestedTransientWrapper);
module.providers.set(TransientService, transientWrapper);
module.providers.set(DefaultScopedParent, parentWrapper);
});
it('should instantiate nested TRANSIENT providers from DEFAULT scope', async () => {
await injector.loadInstance(parentWrapper, module.providers, module);
const parentInstance = parentWrapper.instance;
expect(TransientService.constructorCalled).to.be.true;
expect(NestedTransientService.constructorCalled).to.be.true;
expect(parentInstance.transient).to.be.instanceOf(TransientService);
expect(parentInstance.transient.nested).to.be.instanceOf(
NestedTransientService,
);
expect(parentInstance.transient.nested.value).to.equal(
'nested-initialized',
);
});
});
});