@codefast/di 0.3.16-canary.1 → 0.3.16-canary.3
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.
- package/CHANGELOG.md +18 -0
- package/README.md +4 -4
- package/dist/binding-select.d.mts +1 -1
- package/dist/binding-select.mjs +5 -5
- package/dist/binding.d.mts +28 -28
- package/dist/binding.mjs +8 -8
- package/dist/constraints.d.mts +3 -3
- package/dist/constraints.mjs +2 -2
- package/dist/container.mjs +146 -214
- package/dist/decorators/inject.d.mts +4 -3
- package/dist/decorators/inject.mjs +21 -48
- package/dist/decorators/injectable.mjs +4 -12
- package/dist/decorators/lifecycle-decorators.mjs +11 -72
- package/dist/dependency-graph.mjs +17 -15
- package/dist/environment.d.mts +15 -15
- package/dist/environment.mjs +21 -21
- package/dist/graph-adapters/cytoscape.d.mts +12 -12
- package/dist/graph-adapters/cytoscape.mjs +7 -7
- package/dist/graph-adapters/reactflow.d.mts +15 -15
- package/dist/graph-adapters/reactflow.mjs +6 -9
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +2 -2
- package/dist/inspector.d.mts +3 -2
- package/dist/inspector.mjs +19 -22
- package/dist/lifecycle.mjs +2 -12
- package/dist/metadata/metadata-keys.d.mts +8 -33
- package/dist/metadata/metadata-keys.mjs +8 -21
- package/dist/metadata/metadata-types.d.mts +5 -0
- package/dist/metadata/symbol-metadata-reader.d.mts +1 -0
- package/dist/metadata/symbol-metadata-reader.mjs +11 -33
- package/dist/module.d.mts +1 -1
- package/dist/module.mjs +2 -2
- package/dist/registry.d.mts +4 -4
- package/dist/registry.mjs +26 -45
- package/dist/resolve-options.d.mts +7 -7
- package/dist/resolve-options.mjs +14 -12
- package/dist/resolver.d.mts +15 -10
- package/dist/resolver.mjs +167 -173
- package/dist/token.d.mts +1 -1
- package/dist/token.mjs +4 -4
- package/dist/types.d.mts +14 -8
- package/package.json +40 -13
- package/src/binding-scope.ts +26 -0
- package/src/binding-select.ts +167 -0
- package/src/binding.ts +281 -0
- package/src/constraints.ts +149 -0
- package/src/constructor-type.ts +19 -0
- package/src/container.ts +1213 -0
- package/src/decorators/inject.ts +233 -0
- package/src/decorators/injectable.ts +85 -0
- package/src/decorators/lifecycle-decorators.ts +55 -0
- package/src/dependency-graph.ts +116 -0
- package/src/environment.ts +232 -0
- package/src/errors.ts +262 -0
- package/src/graph-adapters/cytoscape.ts +64 -0
- package/src/graph-adapters/dot.ts +22 -0
- package/src/graph-adapters/reactflow.ts +58 -0
- package/src/index.ts +101 -0
- package/src/inspector.ts +133 -0
- package/src/lifecycle.ts +238 -0
- package/src/metadata/metadata-keys.ts +25 -0
- package/src/metadata/metadata-reader-token.ts +8 -0
- package/src/metadata/metadata-types.ts +53 -0
- package/src/metadata/symbol-metadata-reader.ts +57 -0
- package/src/module.ts +93 -0
- package/src/registry.ts +241 -0
- package/src/resolve-options.ts +42 -0
- package/src/resolver.ts +1837 -0
- package/src/scope.ts +77 -0
- package/src/token.ts +40 -0
- package/src/types.ts +145 -0
- package/dist/graph-adapters/types.d.mts +0 -2
- package/dist/graph-adapters/types.mjs +0 -1
package/dist/token.d.mts
CHANGED
|
@@ -16,7 +16,7 @@ declare function token<Value>(name: string): Token<Value>;
|
|
|
16
16
|
/**
|
|
17
17
|
* @since 0.3.16-canary.0
|
|
18
18
|
*/
|
|
19
|
-
declare function tokenName(
|
|
19
|
+
declare function tokenName(dependency: Token<unknown> | Constructor): string;
|
|
20
20
|
/**
|
|
21
21
|
* @since 0.3.16-canary.0
|
|
22
22
|
*/
|
package/dist/token.mjs
CHANGED
|
@@ -8,15 +8,15 @@ function token(name) {
|
|
|
8
8
|
/**
|
|
9
9
|
* @since 0.3.16-canary.0
|
|
10
10
|
*/
|
|
11
|
-
function tokenName(
|
|
12
|
-
if (typeof
|
|
13
|
-
return
|
|
11
|
+
function tokenName(dependency) {
|
|
12
|
+
if (typeof dependency === "function") return dependency.name;
|
|
13
|
+
return dependency.name;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* @since 0.3.16-canary.0
|
|
17
17
|
*/
|
|
18
18
|
function isToken(value) {
|
|
19
|
-
return typeof value === "object" && value !== null && "name" in value && typeof value["name"] === "string"
|
|
19
|
+
return typeof value === "object" && value !== null && "name" in value && typeof value["name"] === "string";
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
22
|
export { isToken, token, tokenName };
|
package/dist/types.d.mts
CHANGED
|
@@ -2,6 +2,12 @@ import { Constructor } from "./constructor-type.mjs";
|
|
|
2
2
|
import { Token } from "./token.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* A single [tag, value] pair used in slot constraints and resolve hints.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.3.16-canary.0
|
|
9
|
+
*/
|
|
10
|
+
type BindingTag = readonly [tag: string, value: unknown];
|
|
5
11
|
/**
|
|
6
12
|
* Token or class constructor used as a binding / injection / resolve key.
|
|
7
13
|
*
|
|
@@ -40,20 +46,20 @@ interface ResolveOptions {
|
|
|
40
46
|
* Single-tag shorthand — semantics match including one pair in `tags`.
|
|
41
47
|
* Enables fast-path lookup alongside `tags`.
|
|
42
48
|
*/
|
|
43
|
-
tag?:
|
|
44
|
-
tags?: ReadonlyArray<
|
|
49
|
+
tag?: BindingTag;
|
|
50
|
+
tags?: ReadonlyArray<BindingTag>;
|
|
45
51
|
}
|
|
46
52
|
/**
|
|
47
53
|
* @since 0.3.16-canary.0
|
|
48
54
|
*/
|
|
49
|
-
interface
|
|
55
|
+
interface ResolutionFrame {
|
|
50
56
|
readonly tokenName: string;
|
|
51
57
|
readonly scope: BindingScope;
|
|
52
58
|
readonly bindingId: BindingIdentifier;
|
|
53
59
|
readonly kind: BindingKind;
|
|
54
60
|
readonly slot: {
|
|
55
61
|
readonly name: string | undefined;
|
|
56
|
-
readonly tags: ReadonlyArray<
|
|
62
|
+
readonly tags: ReadonlyArray<BindingTag>;
|
|
57
63
|
};
|
|
58
64
|
}
|
|
59
65
|
/**
|
|
@@ -61,9 +67,9 @@ interface MaterializationFrame {
|
|
|
61
67
|
*/
|
|
62
68
|
interface ConstraintContext {
|
|
63
69
|
readonly resolutionPath: ReadonlyArray<string>;
|
|
64
|
-
readonly
|
|
65
|
-
readonly parent:
|
|
66
|
-
readonly ancestors: ReadonlyArray<
|
|
70
|
+
readonly resolutionStack: ReadonlyArray<ResolutionFrame>;
|
|
71
|
+
readonly parent: ResolutionFrame | undefined;
|
|
72
|
+
readonly ancestors: ReadonlyArray<ResolutionFrame>;
|
|
67
73
|
readonly currentResolveHint: ResolveOptions | undefined;
|
|
68
74
|
}
|
|
69
75
|
/**
|
|
@@ -83,4 +89,4 @@ interface ResolutionContext {
|
|
|
83
89
|
*/
|
|
84
90
|
type TokenValue<Type> = Type extends Token<infer Value> ? Value : Type extends Constructor<infer Value> ? Value : never;
|
|
85
91
|
//#endregion
|
|
86
|
-
export { ActivationHandler, BindingIdentifier, BindingKind, BindingScope, ConstraintContext, type Constructor, DeactivationHandler, DependencyKey,
|
|
92
|
+
export { ActivationHandler, BindingIdentifier, BindingKind, BindingScope, BindingTag, ConstraintContext, type Constructor, DeactivationHandler, DependencyKey, ResolutionContext, ResolutionFrame, ResolveOptions, TokenValue };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codefast/di",
|
|
3
|
-
"version": "0.3.16-canary.
|
|
3
|
+
"version": "0.3.16-canary.3",
|
|
4
4
|
"description": "Lightweight dependency injection primitives for Codefast",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codefast",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
|
+
"src",
|
|
21
22
|
"CHANGELOG.md",
|
|
22
23
|
"README.md",
|
|
23
24
|
"LICENSE"
|
|
@@ -45,122 +46,147 @@
|
|
|
45
46
|
},
|
|
46
47
|
"exports": {
|
|
47
48
|
".": {
|
|
49
|
+
"source": "./src/index.ts",
|
|
48
50
|
"types": "./dist/index.d.mts",
|
|
49
51
|
"import": "./dist/index.mjs"
|
|
50
52
|
},
|
|
51
53
|
"./binding": {
|
|
54
|
+
"source": "./src/binding.ts",
|
|
52
55
|
"types": "./dist/binding.d.mts",
|
|
53
56
|
"import": "./dist/binding.mjs"
|
|
54
57
|
},
|
|
55
58
|
"./binding-scope": {
|
|
59
|
+
"source": "./src/binding-scope.ts",
|
|
56
60
|
"types": "./dist/binding-scope.d.mts",
|
|
57
61
|
"import": "./dist/binding-scope.mjs"
|
|
58
62
|
},
|
|
59
63
|
"./binding-select": {
|
|
64
|
+
"source": "./src/binding-select.ts",
|
|
60
65
|
"types": "./dist/binding-select.d.mts",
|
|
61
66
|
"import": "./dist/binding-select.mjs"
|
|
62
67
|
},
|
|
63
68
|
"./constraints": {
|
|
69
|
+
"source": "./src/constraints.ts",
|
|
64
70
|
"types": "./dist/constraints.d.mts",
|
|
65
71
|
"import": "./dist/constraints.mjs"
|
|
66
72
|
},
|
|
67
73
|
"./constructor-type": {
|
|
74
|
+
"source": "./src/constructor-type.ts",
|
|
68
75
|
"types": "./dist/constructor-type.d.mts",
|
|
69
76
|
"import": "./dist/constructor-type.mjs"
|
|
70
77
|
},
|
|
71
78
|
"./container": {
|
|
79
|
+
"source": "./src/container.ts",
|
|
72
80
|
"types": "./dist/container.d.mts",
|
|
73
81
|
"import": "./dist/container.mjs"
|
|
74
82
|
},
|
|
75
83
|
"./decorators/inject": {
|
|
84
|
+
"source": "./src/decorators/inject.ts",
|
|
76
85
|
"types": "./dist/decorators/inject.d.mts",
|
|
77
86
|
"import": "./dist/decorators/inject.mjs"
|
|
78
87
|
},
|
|
79
88
|
"./decorators/injectable": {
|
|
89
|
+
"source": "./src/decorators/injectable.ts",
|
|
80
90
|
"types": "./dist/decorators/injectable.d.mts",
|
|
81
91
|
"import": "./dist/decorators/injectable.mjs"
|
|
82
92
|
},
|
|
83
93
|
"./decorators/lifecycle-decorators": {
|
|
94
|
+
"source": "./src/decorators/lifecycle-decorators.ts",
|
|
84
95
|
"types": "./dist/decorators/lifecycle-decorators.d.mts",
|
|
85
96
|
"import": "./dist/decorators/lifecycle-decorators.mjs"
|
|
86
97
|
},
|
|
87
98
|
"./dependency-graph": {
|
|
99
|
+
"source": "./src/dependency-graph.ts",
|
|
88
100
|
"types": "./dist/dependency-graph.d.mts",
|
|
89
101
|
"import": "./dist/dependency-graph.mjs"
|
|
90
102
|
},
|
|
91
103
|
"./environment": {
|
|
104
|
+
"source": "./src/environment.ts",
|
|
92
105
|
"types": "./dist/environment.d.mts",
|
|
93
106
|
"import": "./dist/environment.mjs"
|
|
94
107
|
},
|
|
95
108
|
"./errors": {
|
|
109
|
+
"source": "./src/errors.ts",
|
|
96
110
|
"types": "./dist/errors.d.mts",
|
|
97
111
|
"import": "./dist/errors.mjs"
|
|
98
112
|
},
|
|
99
113
|
"./graph-adapters/cytoscape": {
|
|
114
|
+
"source": "./src/graph-adapters/cytoscape.ts",
|
|
100
115
|
"types": "./dist/graph-adapters/cytoscape.d.mts",
|
|
101
116
|
"import": "./dist/graph-adapters/cytoscape.mjs"
|
|
102
117
|
},
|
|
103
118
|
"./graph-adapters/dot": {
|
|
119
|
+
"source": "./src/graph-adapters/dot.ts",
|
|
104
120
|
"types": "./dist/graph-adapters/dot.d.mts",
|
|
105
121
|
"import": "./dist/graph-adapters/dot.mjs"
|
|
106
122
|
},
|
|
107
123
|
"./graph-adapters/reactflow": {
|
|
124
|
+
"source": "./src/graph-adapters/reactflow.ts",
|
|
108
125
|
"types": "./dist/graph-adapters/reactflow.d.mts",
|
|
109
126
|
"import": "./dist/graph-adapters/reactflow.mjs"
|
|
110
127
|
},
|
|
111
|
-
"./graph-adapters/types": {
|
|
112
|
-
"types": "./dist/graph-adapters/types.d.mts",
|
|
113
|
-
"import": "./dist/graph-adapters/types.mjs"
|
|
114
|
-
},
|
|
115
128
|
"./inspector": {
|
|
129
|
+
"source": "./src/inspector.ts",
|
|
116
130
|
"types": "./dist/inspector.d.mts",
|
|
117
131
|
"import": "./dist/inspector.mjs"
|
|
118
132
|
},
|
|
119
133
|
"./lifecycle": {
|
|
134
|
+
"source": "./src/lifecycle.ts",
|
|
120
135
|
"types": "./dist/lifecycle.d.mts",
|
|
121
136
|
"import": "./dist/lifecycle.mjs"
|
|
122
137
|
},
|
|
123
138
|
"./metadata/metadata-keys": {
|
|
139
|
+
"source": "./src/metadata/metadata-keys.ts",
|
|
124
140
|
"types": "./dist/metadata/metadata-keys.d.mts",
|
|
125
141
|
"import": "./dist/metadata/metadata-keys.mjs"
|
|
126
142
|
},
|
|
127
143
|
"./metadata/metadata-reader-token": {
|
|
144
|
+
"source": "./src/metadata/metadata-reader-token.ts",
|
|
128
145
|
"types": "./dist/metadata/metadata-reader-token.d.mts",
|
|
129
146
|
"import": "./dist/metadata/metadata-reader-token.mjs"
|
|
130
147
|
},
|
|
131
148
|
"./metadata/metadata-types": {
|
|
149
|
+
"source": "./src/metadata/metadata-types.ts",
|
|
132
150
|
"types": "./dist/metadata/metadata-types.d.mts",
|
|
133
151
|
"import": "./dist/metadata/metadata-types.mjs"
|
|
134
152
|
},
|
|
135
153
|
"./metadata/symbol-metadata-reader": {
|
|
154
|
+
"source": "./src/metadata/symbol-metadata-reader.ts",
|
|
136
155
|
"types": "./dist/metadata/symbol-metadata-reader.d.mts",
|
|
137
156
|
"import": "./dist/metadata/symbol-metadata-reader.mjs"
|
|
138
157
|
},
|
|
139
158
|
"./module": {
|
|
159
|
+
"source": "./src/module.ts",
|
|
140
160
|
"types": "./dist/module.d.mts",
|
|
141
161
|
"import": "./dist/module.mjs"
|
|
142
162
|
},
|
|
143
163
|
"./registry": {
|
|
164
|
+
"source": "./src/registry.ts",
|
|
144
165
|
"types": "./dist/registry.d.mts",
|
|
145
166
|
"import": "./dist/registry.mjs"
|
|
146
167
|
},
|
|
147
168
|
"./resolve-options": {
|
|
169
|
+
"source": "./src/resolve-options.ts",
|
|
148
170
|
"types": "./dist/resolve-options.d.mts",
|
|
149
171
|
"import": "./dist/resolve-options.mjs"
|
|
150
172
|
},
|
|
151
173
|
"./resolver": {
|
|
174
|
+
"source": "./src/resolver.ts",
|
|
152
175
|
"types": "./dist/resolver.d.mts",
|
|
153
176
|
"import": "./dist/resolver.mjs"
|
|
154
177
|
},
|
|
155
178
|
"./scope": {
|
|
179
|
+
"source": "./src/scope.ts",
|
|
156
180
|
"types": "./dist/scope.d.mts",
|
|
157
181
|
"import": "./dist/scope.mjs"
|
|
158
182
|
},
|
|
159
183
|
"./token": {
|
|
184
|
+
"source": "./src/token.ts",
|
|
160
185
|
"types": "./dist/token.d.mts",
|
|
161
186
|
"import": "./dist/token.mjs"
|
|
162
187
|
},
|
|
163
188
|
"./types": {
|
|
189
|
+
"source": "./src/types.ts",
|
|
164
190
|
"types": "./dist/types.d.mts",
|
|
165
191
|
"import": "./dist/types.mjs"
|
|
166
192
|
},
|
|
@@ -170,19 +196,20 @@
|
|
|
170
196
|
"access": "public"
|
|
171
197
|
},
|
|
172
198
|
"devDependencies": {
|
|
173
|
-
"@
|
|
174
|
-
"@
|
|
175
|
-
"@
|
|
199
|
+
"@babel/plugin-proposal-decorators": "8.0.0-rc.6",
|
|
200
|
+
"@rolldown/plugin-babel": "^0.2.3",
|
|
201
|
+
"@types/node": "^25.9.1",
|
|
202
|
+
"@typescript/native-preview": "7.0.0-dev.20260526.1",
|
|
203
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
176
204
|
"expect-type": "^1.3.0",
|
|
177
205
|
"tsdown": "^0.22.0",
|
|
178
|
-
"tsx": "^4.
|
|
206
|
+
"tsx": "^4.22.3",
|
|
179
207
|
"typescript": "^6.0.3",
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"@codefast/typescript-config": "0.3.16-canary.1"
|
|
208
|
+
"vitest": "^4.1.7",
|
|
209
|
+
"@codefast/typescript-config": "0.3.16-canary.3"
|
|
183
210
|
},
|
|
184
211
|
"engines": {
|
|
185
|
-
"node": ">=
|
|
212
|
+
"node": ">=24.0.0"
|
|
186
213
|
},
|
|
187
214
|
"scripts": {
|
|
188
215
|
"build": "tsdown",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Binding } from "#/binding";
|
|
2
|
+
import type { BindingScope } from "#/types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Runtime scope used for validation and introspection. Alias bindings are treated as transient
|
|
6
|
+
* because they defer scope to the aliased target at resolve time.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.3.16-canary.0
|
|
9
|
+
*/
|
|
10
|
+
export function effectiveBindingScope(binding: Binding): BindingScope {
|
|
11
|
+
switch (binding.kind) {
|
|
12
|
+
case "alias":
|
|
13
|
+
return "transient";
|
|
14
|
+
case "class":
|
|
15
|
+
case "constant":
|
|
16
|
+
case "dynamic":
|
|
17
|
+
case "dynamic-async":
|
|
18
|
+
case "resolved":
|
|
19
|
+
case "resolved-async":
|
|
20
|
+
return binding.scope;
|
|
21
|
+
default: {
|
|
22
|
+
const exhaustive: never = binding;
|
|
23
|
+
return exhaustive;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { Binding } from "#/binding";
|
|
2
|
+
import type { BindingTag, ConstraintContext, ResolveOptions } from "#/types";
|
|
3
|
+
import { AmbiguousBindingError } from "#/errors";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Select a single candidate from a list of bindings using slot matching + predicates.
|
|
7
|
+
* Returns undefined if no match, throws AmbiguousBindingError if multiple match.
|
|
8
|
+
*
|
|
9
|
+
* @since 0.3.16-canary.0
|
|
10
|
+
*/
|
|
11
|
+
export function selectBinding(
|
|
12
|
+
bindings: ReadonlyArray<Binding>,
|
|
13
|
+
hint: ResolveOptions | undefined,
|
|
14
|
+
ctx: ConstraintContext,
|
|
15
|
+
tokenDisplayName: string,
|
|
16
|
+
): Binding | undefined {
|
|
17
|
+
const candidates = filterBindings(bindings, hint, ctx);
|
|
18
|
+
if (candidates.length === 0) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
if (candidates.length === 1) {
|
|
22
|
+
return candidates[0];
|
|
23
|
+
}
|
|
24
|
+
// Multiple candidates — check if any is unambiguous (slot-based selection)
|
|
25
|
+
// Slot-based bindings already have last-wins applied in registry, so
|
|
26
|
+
// multiple candidates here means ambiguous predicate-only bindings
|
|
27
|
+
throw new AmbiguousBindingError(
|
|
28
|
+
tokenDisplayName,
|
|
29
|
+
candidates.map((c) => c.id),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Select all candidates matching hint + predicates.
|
|
35
|
+
*
|
|
36
|
+
* @since 0.3.16-canary.0
|
|
37
|
+
*/
|
|
38
|
+
export function selectAllBindings(
|
|
39
|
+
bindings: ReadonlyArray<Binding>,
|
|
40
|
+
hint: ResolveOptions | undefined,
|
|
41
|
+
ctx: ConstraintContext,
|
|
42
|
+
): Array<Binding> {
|
|
43
|
+
return filterBindings(bindings, hint, ctx, "all");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function filterBindings(
|
|
47
|
+
bindings: ReadonlyArray<Binding>,
|
|
48
|
+
hint: ResolveOptions | undefined,
|
|
49
|
+
ctx: ConstraintContext,
|
|
50
|
+
selectionMode: "single" | "all" = "single",
|
|
51
|
+
): Array<Binding> {
|
|
52
|
+
if (hint === undefined) {
|
|
53
|
+
const resultWithoutHint: Array<Binding> = [];
|
|
54
|
+
if (selectionMode === "all") {
|
|
55
|
+
for (const binding of bindings) {
|
|
56
|
+
if (matchesPredicate(binding, ctx)) {
|
|
57
|
+
resultWithoutHint.push(binding);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
for (const binding of bindings) {
|
|
62
|
+
const slot = binding.slot;
|
|
63
|
+
if (slot.name === undefined && slot.tags.length === 0 && matchesPredicate(binding, ctx)) {
|
|
64
|
+
resultWithoutHint.push(binding);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return resultWithoutHint;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const result: Array<Binding> = [];
|
|
72
|
+
for (const binding of bindings) {
|
|
73
|
+
const slotMatched =
|
|
74
|
+
selectionMode === "all"
|
|
75
|
+
? matchesSlotForResolveAll(binding, hint)
|
|
76
|
+
: matchesSlot(binding, hint);
|
|
77
|
+
if (slotMatched && matchesPredicate(binding, ctx)) {
|
|
78
|
+
result.push(binding);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function matchesSlotForResolveAll(binding: Binding, hint: ResolveOptions | undefined): boolean {
|
|
85
|
+
const hasExplicitSlotFilter =
|
|
86
|
+
hint !== undefined &&
|
|
87
|
+
(hint.name !== undefined ||
|
|
88
|
+
(hint.tags !== undefined && hint.tags.length > 0) ||
|
|
89
|
+
hint.tag !== undefined);
|
|
90
|
+
if (!hasExplicitSlotFilter) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return matchesSlot(binding, hint);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function matchesSlot(binding: Binding, hint: ResolveOptions | undefined): boolean {
|
|
97
|
+
const slot = binding.slot;
|
|
98
|
+
const hintName = hint?.name;
|
|
99
|
+
const hintTags = hint?.tags;
|
|
100
|
+
const singleHintTag = hint?.tag;
|
|
101
|
+
const hasHintTags = (hintTags?.length ?? 0) > 0 || singleHintTag !== undefined;
|
|
102
|
+
|
|
103
|
+
// Match by name
|
|
104
|
+
if (slot.name !== undefined) {
|
|
105
|
+
if (hintName === undefined) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
if (slot.name !== hintName) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
} else if (hintName !== undefined) {
|
|
112
|
+
// Binding has no name but hint requests a specific name — no match
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Match by tags — binding's tags must all be present in hint
|
|
117
|
+
if (slot.tags.length > 0) {
|
|
118
|
+
if (!hasHintTags) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
for (const [tagKey, tagValue] of slot.tags) {
|
|
122
|
+
if (!matchHintTag(tagKey, tagValue, hintTags, singleHintTag)) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} else if (hasHintTags) {
|
|
127
|
+
// Binding has no tags but hint requires tags — no match for tagged slots
|
|
128
|
+
// But: default slot (no tags, no name) can match when hint has tags if there are no tag-slotted bindings
|
|
129
|
+
// Actually per spec: resolveAll with tags only returns bindings that have those tags
|
|
130
|
+
// and resolve with tags requires exact match
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function matchHintTag(
|
|
138
|
+
tagKey: string,
|
|
139
|
+
tagValue: unknown,
|
|
140
|
+
hintTags: ReadonlyArray<BindingTag> | undefined,
|
|
141
|
+
singleHintTag: BindingTag | undefined,
|
|
142
|
+
): boolean {
|
|
143
|
+
if (
|
|
144
|
+
singleHintTag !== undefined &&
|
|
145
|
+
singleHintTag[0] === tagKey &&
|
|
146
|
+
Object.is(singleHintTag[1], tagValue)
|
|
147
|
+
) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
if (hintTags === undefined || hintTags.length === 0) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
for (let index = 0; index < hintTags.length; index += 1) {
|
|
154
|
+
const hintTag = hintTags[index]!;
|
|
155
|
+
if (hintTag[0] === tagKey && Object.is(hintTag[1], tagValue)) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function matchesPredicate(binding: Binding, ctx: ConstraintContext): boolean {
|
|
163
|
+
if (binding.predicate === undefined) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
return binding.predicate(ctx);
|
|
167
|
+
}
|