@lppedd/di-wise-neo 0.3.0

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.
Files changed (42) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +488 -0
  3. package/dist/cjs/index.d.ts +772 -0
  4. package/dist/cjs/index.js +1055 -0
  5. package/dist/cjs/index.js.map +1 -0
  6. package/dist/es/index.d.mts +772 -0
  7. package/dist/es/index.mjs +1037 -0
  8. package/dist/es/index.mjs.map +1 -0
  9. package/package.json +77 -0
  10. package/src/container.ts +292 -0
  11. package/src/decorators/autoRegister.ts +24 -0
  12. package/src/decorators/decorators.ts +47 -0
  13. package/src/decorators/index.ts +7 -0
  14. package/src/decorators/inject.ts +42 -0
  15. package/src/decorators/injectAll.ts +45 -0
  16. package/src/decorators/injectable.ts +61 -0
  17. package/src/decorators/optional.ts +39 -0
  18. package/src/decorators/optionalAll.ts +42 -0
  19. package/src/decorators/scoped.ts +32 -0
  20. package/src/defaultContainer.ts +519 -0
  21. package/src/errors.ts +47 -0
  22. package/src/index.ts +16 -0
  23. package/src/inject.ts +88 -0
  24. package/src/injectAll.ts +21 -0
  25. package/src/injectionContext.ts +46 -0
  26. package/src/injector.ts +117 -0
  27. package/src/metadata.ts +41 -0
  28. package/src/middleware.ts +85 -0
  29. package/src/optional.ts +65 -0
  30. package/src/optionalAll.ts +19 -0
  31. package/src/provider.ts +61 -0
  32. package/src/scope.ts +8 -0
  33. package/src/token.ts +84 -0
  34. package/src/tokenRegistry.ts +165 -0
  35. package/src/tokensRef.ts +46 -0
  36. package/src/utils/context.ts +19 -0
  37. package/src/utils/disposable.ts +10 -0
  38. package/src/utils/invariant.ts +6 -0
  39. package/src/utils/keyedStack.ts +26 -0
  40. package/src/utils/typeName.ts +28 -0
  41. package/src/utils/weakRefMap.ts +28 -0
  42. package/src/valueRef.ts +3 -0
@@ -0,0 +1,46 @@
1
+ import type { Container } from "./container";
2
+ import { assert } from "./errors";
3
+ import type { Provider } from "./provider";
4
+ import type { Scope } from "./scope";
5
+ import { createInjectionContext } from "./utils/context";
6
+ import { KeyedStack } from "./utils/keyedStack";
7
+ import { WeakRefMap } from "./utils/weakRefMap";
8
+ import type { ValueRef } from "./valueRef";
9
+
10
+ // @internal
11
+ export interface ResolutionFrame {
12
+ readonly scope: Exclude<Scope, typeof Scope.Inherited>;
13
+ readonly provider: Provider;
14
+ }
15
+
16
+ // @internal
17
+ export interface Resolution {
18
+ readonly stack: KeyedStack<Provider, ResolutionFrame>;
19
+ readonly values: WeakRefMap<Provider, ValueRef>;
20
+ readonly dependents: WeakRefMap<Provider, ValueRef>;
21
+ }
22
+
23
+ // @internal
24
+ export interface InjectionContext {
25
+ readonly container: Container;
26
+ readonly resolution: Resolution;
27
+ }
28
+
29
+ // @internal
30
+ export function createResolution(): Resolution {
31
+ return {
32
+ stack: new KeyedStack(),
33
+ values: new WeakRefMap(),
34
+ dependents: new WeakRefMap(),
35
+ };
36
+ }
37
+
38
+ // @internal
39
+ export const [provideInjectionContext, useInjectionContext] = createInjectionContext<InjectionContext>();
40
+
41
+ // @internal
42
+ export function ensureInjectionContext(fn: Function): InjectionContext {
43
+ const context = useInjectionContext();
44
+ assert(context, `${fn.name}() can only be invoked within an injection context`);
45
+ return context;
46
+ }
@@ -0,0 +1,117 @@
1
+ import { inject } from "./inject";
2
+ import { injectAll } from "./injectAll";
3
+ import { ensureInjectionContext, provideInjectionContext, useInjectionContext } from "./injectionContext";
4
+ import { optional } from "./optional";
5
+ import { optionalAll } from "./optionalAll";
6
+ import type { Constructor, Token, Type } from "./token";
7
+ import { Build } from "./tokenRegistry";
8
+
9
+ /**
10
+ * Injector API.
11
+ */
12
+ export interface Injector {
13
+ /**
14
+ * Injects the instance associated with the given class.
15
+ *
16
+ * Throws an error if the class is not registered in the container.
17
+ */
18
+ inject<Instance extends object>(Class: Constructor<Instance>): Instance;
19
+
20
+ /**
21
+ * Injects the value associated with the given token.
22
+ *
23
+ * Throws an error if the token is not registered in the container.
24
+ */
25
+ inject<Value>(token: Token<Value>): Value;
26
+
27
+ /**
28
+ * Injects all instances provided by the registrations associated with the given class.
29
+ *
30
+ * Throws an error if the class is not registered in the container.
31
+ */
32
+ injectAll<Instance extends object>(Class: Constructor<Instance>): Instance[];
33
+
34
+ /**
35
+ * Injects all values provided by the registrations associated with the given token.
36
+ *
37
+ * Throws an error if the token is not registered in the container.
38
+ */
39
+ injectAll<Value>(token: Token<Value>): NonNullable<Value>[];
40
+
41
+ /**
42
+ * Injects the instance associated with the given class,
43
+ * or `undefined` if the class is not registered in the container.
44
+ */
45
+ optional<Instance extends object>(Class: Constructor<Instance>): Instance | undefined;
46
+
47
+ /**
48
+ * Injects the value associated with the given token,
49
+ * or `undefined` if the token is not registered in the container.
50
+ */
51
+ optional<Value>(token: Token<Value>): Value | undefined;
52
+
53
+ /**
54
+ * Injects all instances provided by the registrations associated with the given class,
55
+ * or an empty array if the class is not registered in the container.
56
+ */
57
+ optionalAll<Instance extends object>(Class: Constructor<Instance>): Instance[];
58
+
59
+ /**
60
+ * Injects all values provided by the registrations associated with the given token,
61
+ * or an empty array if the token is not registered in the container.
62
+ */
63
+ optionalAll<Value>(token: Token<Value>): NonNullable<Value>[];
64
+ }
65
+
66
+ /**
67
+ * Injector token for dynamic injections.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * class Wizard {
72
+ * private injector = inject(Injector);
73
+ * private wand?: Wand;
74
+ *
75
+ * getWand(): Wand {
76
+ * return (this.wand ??= this.injector.inject(Wand));
77
+ * }
78
+ * }
79
+ *
80
+ * const wizard = container.resolve(Wizard);
81
+ * wizard.getWand(); // => Wand
82
+ * ```
83
+ */
84
+ export const Injector: Type<Injector> = /*@__PURE__*/ Build(function Injector() {
85
+ const context = ensureInjectionContext(Injector);
86
+ const resolution = context.resolution;
87
+
88
+ const dependentFrame = resolution.stack.peek();
89
+ const dependentRef = dependentFrame && resolution.dependents.get(dependentFrame.provider);
90
+
91
+ function withCurrentContext<R>(fn: () => R): R {
92
+ if (useInjectionContext()) {
93
+ return fn();
94
+ }
95
+
96
+ const cleanups = [
97
+ provideInjectionContext(context),
98
+ dependentFrame && resolution.stack.push(dependentFrame.provider, dependentFrame),
99
+ dependentRef && resolution.dependents.set(dependentFrame.provider, dependentRef),
100
+ ];
101
+
102
+ try {
103
+ return fn();
104
+ } finally {
105
+ for (const cleanup of cleanups) {
106
+ cleanup?.();
107
+ }
108
+ }
109
+ }
110
+
111
+ return {
112
+ inject: <T>(token: Token<T>) => withCurrentContext(() => inject(token)),
113
+ injectAll: <T>(token: Token<T>) => withCurrentContext(() => injectAll(token)),
114
+ optional: <T>(token: Token<T>) => withCurrentContext(() => optional(token)),
115
+ optionalAll: <T>(token: Token<T>) => withCurrentContext(() => optionalAll(token)),
116
+ };
117
+ });
@@ -0,0 +1,41 @@
1
+ import type { ClassProvider } from "./provider";
2
+ import type { Scope } from "./scope";
3
+ import type { Constructor } from "./token";
4
+ import type { Dependencies } from "./tokenRegistry";
5
+ import type { TokensRef } from "./tokensRef";
6
+
7
+ // @internal
8
+ export interface Metadata<This extends object = any> {
9
+ autoRegister?: boolean;
10
+ scope?: Scope;
11
+ tokensRef: TokensRef<This>;
12
+ provider: ClassProvider<This>;
13
+ dependencies: Dependencies;
14
+ }
15
+
16
+ // @internal
17
+ export function getMetadata<T extends object>(Class: Constructor<T>): Metadata<T> {
18
+ let metadata = metadataMap.get(Class);
19
+
20
+ if (!metadata) {
21
+ metadataMap.set(
22
+ Class,
23
+ (metadata = {
24
+ tokensRef: {
25
+ getRefTokens: () => new Set(),
26
+ },
27
+ provider: {
28
+ useClass: Class,
29
+ },
30
+ dependencies: {
31
+ constructor: [],
32
+ methods: new Map(),
33
+ },
34
+ }),
35
+ );
36
+ }
37
+
38
+ return metadata;
39
+ }
40
+
41
+ const metadataMap = new WeakMap<Constructor<object>, Metadata>();
@@ -0,0 +1,85 @@
1
+ import type { Container } from "./container";
2
+
3
+ /**
4
+ * Composer API for middleware functions.
5
+ */
6
+ export interface MiddlewareComposer {
7
+ /**
8
+ * Add a middleware function to the composer.
9
+ */
10
+ use<MethodKey extends keyof Container>(
11
+ key: MethodKey,
12
+ wrap: Container[MethodKey] extends Function
13
+ ? (next: Container[MethodKey]) => Container[MethodKey]
14
+ : never,
15
+ ): MiddlewareComposer;
16
+ }
17
+
18
+ /**
19
+ * Middleware function that can be used to extend the container.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const logger: Middleware = (composer, _api) => {
24
+ * composer
25
+ * .use("resolve", (next) => (...args) => {
26
+ * console.log("resolve", args);
27
+ * return next(...args);
28
+ * })
29
+ * .use("resolveAll", (next) => (...args) => {
30
+ * console.log("resolveAll", args);
31
+ * return next(...args);
32
+ * });
33
+ * };
34
+ * ```
35
+ */
36
+ export interface Middleware {
37
+ (composer: MiddlewareComposer, api: Readonly<Container>): void;
38
+ }
39
+
40
+ /**
41
+ * Apply middleware functions to a container.
42
+ *
43
+ * Middlewares are applied in array order, but execute in reverse order.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const container = applyMiddleware(
48
+ * createContainer(),
49
+ * [A, B],
50
+ * );
51
+ * ```
52
+ *
53
+ * The execution order will be:
54
+ *
55
+ * 1. B before
56
+ * 2. A before
57
+ * 3. original function
58
+ * 4. A after
59
+ * 5. B after
60
+ *
61
+ * This allows outer middlewares to wrap and control the behavior of inner middlewares.
62
+ */
63
+ export function applyMiddleware(container: Container, middlewares: Middleware[]): Container {
64
+ const composer: MiddlewareComposer = {
65
+ use(key, wrap): MiddlewareComposer {
66
+ // We need to bind the 'this' context of the function to the container
67
+ // before passing it to the middleware wrapper.
68
+ //
69
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call
70
+ const fn = (container[key] as any).bind(container);
71
+
72
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
73
+ container[key] = wrap(fn);
74
+ return composer;
75
+ },
76
+ };
77
+
78
+ const api = (container.api ||= { ...container });
79
+
80
+ for (const middleware of middlewares) {
81
+ middleware(composer, api);
82
+ }
83
+
84
+ return container;
85
+ }
@@ -0,0 +1,65 @@
1
+ import { ensureInjectionContext } from "./injectionContext";
2
+ import type { Constructor, Token } from "./token";
3
+
4
+ /**
5
+ * Injects the instance associated with the given class,
6
+ * or `undefined` if the class is not registered in the container.
7
+ */
8
+ export function optional<Instance extends object>(Class: Constructor<Instance>): Instance | undefined;
9
+
10
+ /**
11
+ * Injects the value associated with the given token,
12
+ * or `undefined` if the token is not registered in the container.
13
+ */
14
+ export function optional<Value>(token: Token<Value>): Value | undefined;
15
+
16
+ export function optional<T>(token: Token<T>): T | undefined {
17
+ const context = ensureInjectionContext(optional);
18
+ return context.container.resolve(token, true);
19
+ }
20
+
21
+ /**
22
+ * Injects the instance associated with the given class,
23
+ * or `undefined` if the class is not registered in the container.
24
+ *
25
+ * Compared to {@link optional}, `optionalBy` accepts a `thisArg` argument
26
+ * (the containing class) which is used to resolve circular dependencies.
27
+ *
28
+ * @param thisArg - The containing instance, used to help resolve circular dependencies.
29
+ * @param Class - The class to resolve.
30
+ */
31
+ export function optionalBy<Instance extends object>(
32
+ thisArg: any,
33
+ Class: Constructor<Instance>,
34
+ ): Instance | undefined;
35
+
36
+ /**
37
+ * Injects the value associated with the given token,
38
+ * or `undefined` if the token is not registered in the container.
39
+ *
40
+ * Compared to {@link optional}, `optionalBy` accepts a `thisArg` argument
41
+ * (the containing class) which is used to resolve circular dependencies.
42
+ *
43
+ * @param thisArg - The containing instance, used to help resolve circular dependencies.
44
+ * @param token - The token to resolve.
45
+ */
46
+ export function optionalBy<Value>(thisArg: any, token: Token<Value>): Value | undefined;
47
+
48
+ export function optionalBy<T>(thisArg: any, token: Token<T>): T | undefined {
49
+ const context = ensureInjectionContext(optionalBy);
50
+ const resolution = context.resolution;
51
+ const currentFrame = resolution.stack.peek();
52
+
53
+ if (!currentFrame) {
54
+ return optional(token);
55
+ }
56
+
57
+ const currentRef = { current: thisArg };
58
+ const cleanup = resolution.dependents.set(currentFrame.provider, currentRef);
59
+
60
+ try {
61
+ return optional(token);
62
+ } finally {
63
+ cleanup();
64
+ }
65
+ }
@@ -0,0 +1,19 @@
1
+ import { ensureInjectionContext } from "./injectionContext";
2
+ import type { Constructor, Token } from "./token";
3
+
4
+ /**
5
+ * Injects all instances provided by the registrations associated with the given class,
6
+ * or an empty array if the class is not registered in the container.
7
+ */
8
+ export function optionalAll<Instance extends object>(Class: Constructor<Instance>): Instance[];
9
+
10
+ /**
11
+ * Injects all values provided by the registrations associated with the given token,
12
+ * or an empty array if the token is not registered in the container.
13
+ */
14
+ export function optionalAll<Value>(token: Token<Value>): NonNullable<Value>[];
15
+
16
+ export function optionalAll<T>(token: Token<T>): NonNullable<T>[] {
17
+ const context = ensureInjectionContext(optionalAll);
18
+ return context.container.resolveAll(token, true);
19
+ }
@@ -0,0 +1,61 @@
1
+ import type { Constructor, Token } from "./token";
2
+
3
+ /**
4
+ * Provides a class instance for a token via a class constructor.
5
+ */
6
+ export interface ClassProvider<Instance extends object> {
7
+ readonly useClass: Constructor<Instance>;
8
+ }
9
+
10
+ /**
11
+ * Provides a value for a token via another existing token.
12
+ */
13
+ export interface ExistingProvider<Value> {
14
+ readonly useExisting: Token<Value>;
15
+ }
16
+
17
+ /**
18
+ * Provides a value for a token via a factory function.
19
+ *
20
+ * The factory function runs inside the injection context
21
+ * and can thus access dependencies via {@link inject}.
22
+ */
23
+ export interface FactoryProvider<Value> {
24
+ readonly useFactory: (...args: []) => Value;
25
+ }
26
+
27
+ /**
28
+ * Provides a direct - already constructed - value for a token.
29
+ */
30
+ export interface ValueProvider<T> {
31
+ readonly useValue: T;
32
+ }
33
+
34
+ /**
35
+ * A token provider.
36
+ */
37
+ export type Provider<Value = any> =
38
+ | ClassProvider<Value & object>
39
+ | ExistingProvider<Value>
40
+ | FactoryProvider<Value>
41
+ | ValueProvider<Value>;
42
+
43
+ // @internal
44
+ export function isClassProvider<T>(provider: Provider<T>): provider is ClassProvider<T & object> {
45
+ return "useClass" in provider;
46
+ }
47
+
48
+ // @internal
49
+ export function isExistingProvider<T>(provider: Provider<T>): provider is ExistingProvider<T> {
50
+ return "useExisting" in provider;
51
+ }
52
+
53
+ // @internal
54
+ export function isFactoryProvider<T>(provider: Provider<T>): provider is FactoryProvider<T> {
55
+ return "useFactory" in provider;
56
+ }
57
+
58
+ // @internal
59
+ export function isValueProvider<T>(provider: Provider<T>): provider is ValueProvider<T> {
60
+ return "useValue" in provider;
61
+ }
package/src/scope.ts ADDED
@@ -0,0 +1,8 @@
1
+ export const Scope = {
2
+ Inherited: "Inherited",
3
+ Transient: "Transient",
4
+ Resolution: "Resolution",
5
+ Container: "Container",
6
+ } as const;
7
+
8
+ export type Scope = (typeof Scope)[keyof typeof Scope];
package/src/token.ts ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Type API.
3
+ */
4
+ export interface Type<A> {
5
+ /**
6
+ * Name of the type.
7
+ */
8
+ readonly name: string;
9
+
10
+ /**
11
+ * Create an intersection type from another type.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const A = Type<A>("A");
16
+ * const B = Type<B>("B");
17
+ *
18
+ * A.inter("I", B); // => Type<A & B>
19
+ * ```
20
+ */
21
+ inter<B>(typeName: string, B: Type<B>): Type<A & B>;
22
+
23
+ /**
24
+ * Create a union type from another type.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const A = Type<A>("A");
29
+ * const B = Type<B>("B");
30
+ *
31
+ * A.union("U", B); // => Type<A | B>
32
+ * ```
33
+ */
34
+ union<B>(typeName: string, B: Type<B>): Type<A | B>;
35
+ }
36
+
37
+ /**
38
+ * Constructor type.
39
+ */
40
+ export interface Constructor<Instance extends object> {
41
+ new (...args: any[]): Instance;
42
+ readonly name: string;
43
+ readonly length: number;
44
+ }
45
+
46
+ /**
47
+ * Token type.
48
+ */
49
+ export type Token<Value = any> = [Value] extends [object] // Avoids distributive union behavior
50
+ ? Type<Value> | Constructor<Value>
51
+ : Type<Value>;
52
+
53
+ /**
54
+ * Describes a {@link Token} array with at least one element.
55
+ */
56
+ export type Tokens<Value = any> = [Token<Value>, ...Token<Value>[]];
57
+
58
+ /**
59
+ * Create a type token.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * const Spell = Type<Spell>("Spell");
64
+ * ```
65
+ *
66
+ * @__NO_SIDE_EFFECTS__
67
+ */
68
+ export function Type<T>(typeName: string): Type<T> {
69
+ const type = {
70
+ name: `Type<${typeName}>`,
71
+ inter: Type,
72
+ union: Type,
73
+ toString(): string {
74
+ return type.name;
75
+ },
76
+ };
77
+
78
+ return type;
79
+ }
80
+
81
+ // @internal
82
+ export function isConstructor<T>(token: Type<T> | Constructor<T & object>): token is Constructor<T & object> {
83
+ return typeof token == "function";
84
+ }
@@ -0,0 +1,165 @@
1
+ import { assert } from "./errors";
2
+ import type { FactoryProvider, Provider } from "./provider";
3
+ import { Scope } from "./scope";
4
+ import { type Constructor, type Token, Type } from "./token";
5
+ import type { TokenRef } from "./tokensRef";
6
+ import { getTypeName } from "./utils/typeName";
7
+ import type { ValueRef } from "./valueRef";
8
+
9
+ /**
10
+ * Token registration options.
11
+ */
12
+ export interface RegistrationOptions {
13
+ /**
14
+ * The scope of the registration.
15
+ */
16
+ readonly scope?: Scope;
17
+ }
18
+
19
+ // @internal
20
+ export type Decorator = "Inject" | "InjectAll" | "Optional" | "OptionalAll";
21
+
22
+ // @internal
23
+ export interface MethodDependency {
24
+ readonly decorator: Decorator;
25
+ readonly tokenRef: TokenRef;
26
+
27
+ // The index of the annotated parameter (zero-based)
28
+ readonly index: number;
29
+ }
30
+
31
+ // @internal
32
+ export interface Dependencies {
33
+ readonly constructor: MethodDependency[];
34
+ readonly methods: Map<string | symbol, MethodDependency[]>;
35
+ }
36
+
37
+ // @internal
38
+ export interface Registration<T = any> {
39
+ value?: ValueRef<T>;
40
+ readonly provider: Provider<T>;
41
+ readonly options?: RegistrationOptions;
42
+ readonly dependencies?: Dependencies;
43
+ }
44
+
45
+ // @internal
46
+ export class TokenRegistry {
47
+ private readonly myMap = new Map<Token, Registration[]>();
48
+
49
+ constructor(private readonly parent: TokenRegistry | undefined) {}
50
+
51
+ get<T>(token: Token<T>): Registration<T> | undefined {
52
+ // To clarify, at(-1) means we take the last added registration for this token
53
+ return this.getAll(token)?.at(-1);
54
+ }
55
+
56
+ getAll<T>(token: Token<T>): Registration<T>[] | undefined {
57
+ const internal = internals.get(token);
58
+ return (internal && [internal]) || this.getAllFromParent(token);
59
+ }
60
+
61
+ //
62
+ // set(...) overloads added because of TS distributive conditional types.
63
+ //
64
+ // TODO(Edoardo): is there a better way? Maybe refactor the Token<T> type
65
+ // into two types, TokenObject<T extends object> | Token<T>
66
+ //
67
+
68
+ set<T extends object>(token: Type<T> | Constructor<T>, registration: Registration<T>): void;
69
+ set<T>(token: Token<T>, registration: Registration<T>): void;
70
+ set<T>(token: Token<T>, registration: Registration<T>): void {
71
+ assert(!internals.has(token), `cannot register reserved token ${token.name}`);
72
+
73
+ let registrations = this.myMap.get(token);
74
+
75
+ if (!registrations) {
76
+ this.myMap.set(token, (registrations = []));
77
+ }
78
+
79
+ registrations.push(registration);
80
+ }
81
+
82
+ delete<T>(token: Token<T>): Registration<T>[] | undefined {
83
+ const registrations = this.myMap.get(token);
84
+ this.myMap.delete(token);
85
+ return registrations;
86
+ }
87
+
88
+ deleteAll(): [Token[], Registration[]] {
89
+ const tokens = Array.from(this.myMap.keys());
90
+ const registrations = Array.from(this.myMap.values()).flat();
91
+ this.myMap.clear();
92
+ return [tokens, registrations];
93
+ }
94
+
95
+ clearRegistrations(): unknown[] {
96
+ const values = new Set<unknown>();
97
+
98
+ for (const registrations of this.myMap.values()) {
99
+ for (let i = 0; i < registrations.length; i++) {
100
+ const registration = registrations[i]!;
101
+ const value = registration.value;
102
+
103
+ if (value) {
104
+ values.add(value.current);
105
+ }
106
+
107
+ registrations[i] = {
108
+ ...registration,
109
+ value: undefined,
110
+ };
111
+ }
112
+ }
113
+
114
+ return Array.from(values);
115
+ }
116
+
117
+ private getAllFromParent<T>(token: Token<T>): Registration<T>[] | undefined {
118
+ const registrations = this.myMap.get(token);
119
+ return registrations || this.parent?.getAllFromParent(token);
120
+ }
121
+ }
122
+
123
+ // @internal
124
+ export function isBuilder(provider: Provider): boolean {
125
+ return builders.has(provider);
126
+ }
127
+
128
+ /**
129
+ * Create a one-off type token from a factory function.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * class Wizard {
134
+ * wand = inject(
135
+ * Build(() => {
136
+ * const wand = inject(Wand);
137
+ * wand.owner = this;
138
+ * // ...
139
+ * return wand;
140
+ * }),
141
+ * );
142
+ * }
143
+ * ```
144
+ *
145
+ * @__NO_SIDE_EFFECTS__
146
+ */
147
+ export function Build<Value>(factory: (...args: []) => Value): Type<Value> {
148
+ const token = Type<Value>(`Build<${getTypeName(factory)}>`);
149
+ const provider: FactoryProvider<Value> = {
150
+ useFactory: factory,
151
+ };
152
+
153
+ internals.set(token, {
154
+ provider: provider,
155
+ options: {
156
+ scope: Scope.Transient,
157
+ },
158
+ });
159
+
160
+ builders.add(provider);
161
+ return token;
162
+ }
163
+
164
+ const internals = new WeakMap<Token, Registration>();
165
+ const builders = new WeakSet<Provider>();