Skip to content

Commit 696f003

Browse files
AleksanderBodurrialxhub
authored andcommitted
fix(core): mutation bug in getDependenciesFromInjectable (angular#52450)
Previously, we would modified `dep.flags` directly to convert injection flags to booleans. This caused a mutation bug where subsequent calls to `getDependenciesFromInjectable` would result in the flags object containing false for every injection flag. Now, we stop modifying `dep.flags` directly and instead assign the converted flags to a new object. PR Close angular#52450
1 parent e5c3b25 commit 696f003

File tree

1 file changed

+15
-16
lines changed

1 file changed

+15
-16
lines changed

packages/core/src/render3/util/injector_discovery_utils.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,32 @@ export function getDependenciesFromInjectable<T>(
5757
const resolutionPath = getInjectorResolutionPath(injector);
5858

5959
const dependencies = unformattedDependencies.map(dep => {
60+
// injectedIn contains private fields, so we omit it from the response
61+
const formattedDependency: Omit<InjectedService, 'injectedIn'> = {
62+
value: dep.value,
63+
};
64+
6065
// convert injection flags to booleans
6166
const flags = dep.flags as InternalInjectFlags;
62-
dep.flags = {
67+
formattedDependency.flags = {
6368
optional: (InternalInjectFlags.Optional & flags) === InternalInjectFlags.Optional,
6469
host: (InternalInjectFlags.Host & flags) === InternalInjectFlags.Host,
6570
self: (InternalInjectFlags.Self & flags) === InternalInjectFlags.Self,
6671
skipSelf: (InternalInjectFlags.SkipSelf & flags) === InternalInjectFlags.SkipSelf,
6772
};
6873

74+
6975
// find the injector that provided the dependency
7076
for (let i = 0; i < resolutionPath.length; i++) {
7177
const injectorToCheck = resolutionPath[i];
7278

7379
// if skipSelf is true we skip the first injector
74-
if (i === 0 && dep.flags.skipSelf) {
80+
if (i === 0 && formattedDependency.flags.skipSelf) {
7581
continue;
7682
}
7783

7884
// host only applies to NodeInjectors
79-
if (dep.flags.host && injectorToCheck instanceof EnvironmentInjector) {
85+
if (formattedDependency.flags.host && injectorToCheck instanceof EnvironmentInjector) {
8086
break;
8187
}
8288

@@ -88,36 +94,29 @@ export function getDependenciesFromInjectable<T>(
8894
// in the resolution path by using the host flag. This is done to make sure that we've found
8995
// the correct providing injector, and not a node injector that is connected to our path via
9096
// a router outlet.
91-
if (dep.flags.host) {
97+
if (formattedDependency.flags.host) {
9298
const firstInjector = resolutionPath[0];
93-
const lookupFromFirstInjector =
94-
firstInjector.get(dep.token as Type<unknown>, null, {...dep.flags, optional: true});
99+
const lookupFromFirstInjector = firstInjector.get(
100+
dep.token as Type<unknown>, null, {...formattedDependency.flags, optional: true});
95101

96102
if (lookupFromFirstInjector !== null) {
97-
dep.providedIn = injectorToCheck;
103+
formattedDependency.providedIn = injectorToCheck;
98104
}
99105

100106
break;
101107
}
102108

103-
dep.providedIn = injectorToCheck;
109+
formattedDependency.providedIn = injectorToCheck;
104110
break;
105111
}
106112

107113
// if self is true we stop after the first injector
108-
if (i === 0 && dep.flags.self) {
114+
if (i === 0 && formattedDependency.flags.self) {
109115
break;
110116
}
111117
}
112118

113-
// injectedIn contains private fields, so we omit it from the response
114-
const formattedDependency: Omit<InjectedService, 'injectedIn'> = {
115-
value: dep.value,
116-
};
117-
118119
if (dep.token) formattedDependency.token = dep.token;
119-
if (dep.flags) formattedDependency.flags = dep.flags;
120-
if (dep.providedIn) formattedDependency.providedIn = dep.providedIn;
121120

122121
return formattedDependency;
123122
});

0 commit comments

Comments
 (0)