@codefast/di 0.7.1 → 0.8.1

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 (218) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +242 -159
  3. package/dist/ambient/active-container.d.ts +1 -2
  4. package/dist/ambient/active-container.js +1 -2
  5. package/dist/container/binding-builders.d.ts +1 -2
  6. package/dist/container/binding-builders.js +5 -7
  7. package/dist/container/container.d.ts +1 -2
  8. package/dist/container/container.js +4 -6
  9. package/dist/core/binding-scope.d.ts +1 -2
  10. package/dist/core/binding-scope.js +1 -2
  11. package/dist/core/binding.d.ts +16 -4
  12. package/dist/core/binding.js +30 -6
  13. package/dist/core/constraint-requirement.d.ts +1 -2
  14. package/dist/core/constraint-requirement.js +1 -2
  15. package/dist/core/constructor-type.d.ts +1 -2
  16. package/dist/core/constructor-type.js +1 -2
  17. package/dist/core/map-upsert.d.ts +1 -2
  18. package/dist/core/map-upsert.js +1 -2
  19. package/dist/core/module.d.ts +1 -2
  20. package/dist/core/module.js +1 -2
  21. package/dist/core/registry.d.ts +1 -5
  22. package/dist/core/registry.js +15 -63
  23. package/dist/core/tag.d.ts +27 -2
  24. package/dist/core/tag.js +55 -13
  25. package/dist/core/token.d.ts +1 -2
  26. package/dist/core/token.js +1 -2
  27. package/dist/core/types.d.ts +1 -2
  28. package/dist/core/types.js +1 -2
  29. package/dist/decorators/inject.d.ts +1 -2
  30. package/dist/decorators/inject.js +1 -2
  31. package/dist/decorators/injectable.d.ts +1 -2
  32. package/dist/decorators/injectable.js +1 -2
  33. package/dist/decorators/lifecycle-decorators.d.ts +1 -2
  34. package/dist/decorators/lifecycle-decorators.js +1 -2
  35. package/dist/errors/diagnostics.d.ts +1 -2
  36. package/dist/errors/diagnostics.js +1 -2
  37. package/dist/errors/errors.d.ts +1 -2
  38. package/dist/errors/errors.js +29 -5
  39. package/dist/index.d.ts +2 -3
  40. package/dist/index.js +2 -3
  41. package/dist/injection/descriptor.d.ts +1 -2
  42. package/dist/injection/descriptor.js +1 -2
  43. package/dist/injection/resolve-options.d.ts +18 -14
  44. package/dist/injection/resolve-options.js +70 -17
  45. package/dist/introspection/dependency-graph.d.ts +1 -2
  46. package/dist/introspection/dependency-graph.js +23 -11
  47. package/dist/introspection/graph-adapters/cytoscape.d.ts +1 -2
  48. package/dist/introspection/graph-adapters/cytoscape.js +1 -2
  49. package/dist/introspection/graph-adapters/dot.d.ts +1 -2
  50. package/dist/introspection/graph-adapters/dot.js +1 -2
  51. package/dist/introspection/graph-adapters/mermaid.d.ts +1 -2
  52. package/dist/introspection/graph-adapters/mermaid.js +1 -2
  53. package/dist/introspection/graph-adapters/reactflow.d.ts +1 -2
  54. package/dist/introspection/graph-adapters/reactflow.js +1 -2
  55. package/dist/introspection/inspector.d.ts +1 -2
  56. package/dist/introspection/inspector.js +1 -2
  57. package/dist/lifecycle/lifecycle-manager.d.ts +1 -2
  58. package/dist/lifecycle/lifecycle-manager.js +1 -2
  59. package/dist/lifecycle/scope-manager.d.ts +1 -2
  60. package/dist/lifecycle/scope-manager.js +1 -2
  61. package/dist/metadata/metadata-keys.d.ts +1 -2
  62. package/dist/metadata/metadata-keys.js +1 -2
  63. package/dist/metadata/metadata-reader-token.d.ts +1 -2
  64. package/dist/metadata/metadata-reader-token.js +1 -2
  65. package/dist/metadata/metadata-types.d.ts +1 -2
  66. package/dist/metadata/metadata-types.js +1 -2
  67. package/dist/metadata/symbol-metadata-reader.d.ts +1 -2
  68. package/dist/metadata/symbol-metadata-reader.js +1 -2
  69. package/dist/metadata/verifying-metadata-reader.d.ts +1 -2
  70. package/dist/metadata/verifying-metadata-reader.js +1 -2
  71. package/dist/resolution/cache/activation-need.d.ts +1 -2
  72. package/dist/resolution/cache/activation-need.js +1 -2
  73. package/dist/resolution/cache/binding-lookup-cache.d.ts +2 -5
  74. package/dist/resolution/cache/binding-lookup-cache.js +2 -40
  75. package/dist/resolution/cache/class-introspector.d.ts +1 -2
  76. package/dist/resolution/cache/class-introspector.js +1 -2
  77. package/dist/resolution/context.d.ts +1 -2
  78. package/dist/resolution/context.js +1 -2
  79. package/dist/resolution/path/resolution-path.d.ts +1 -2
  80. package/dist/resolution/path/resolution-path.js +1 -2
  81. package/dist/resolution/plan/instantiation-plan.d.ts +5 -14
  82. package/dist/resolution/plan/instantiation-plan.js +10 -29
  83. package/dist/resolution/resolver.d.ts +13 -7
  84. package/dist/resolution/resolver.js +107 -143
  85. package/dist/resolution/select/binding-select.d.ts +5 -7
  86. package/dist/resolution/select/binding-select.js +19 -22
  87. package/dist/resolution/select/constraints.d.ts +1 -2
  88. package/dist/resolution/select/constraints.js +1 -2
  89. package/package.json +6 -58
  90. package/dist/ambient/active-container.d.ts.map +0 -1
  91. package/dist/ambient/active-container.js.map +0 -1
  92. package/dist/container/binding-builders.d.ts.map +0 -1
  93. package/dist/container/binding-builders.js.map +0 -1
  94. package/dist/container/container.d.ts.map +0 -1
  95. package/dist/container/container.js.map +0 -1
  96. package/dist/core/binding-scope.d.ts.map +0 -1
  97. package/dist/core/binding-scope.js.map +0 -1
  98. package/dist/core/binding.d.ts.map +0 -1
  99. package/dist/core/binding.js.map +0 -1
  100. package/dist/core/constraint-requirement.d.ts.map +0 -1
  101. package/dist/core/constraint-requirement.js.map +0 -1
  102. package/dist/core/constructor-type.d.ts.map +0 -1
  103. package/dist/core/constructor-type.js.map +0 -1
  104. package/dist/core/map-upsert.d.ts.map +0 -1
  105. package/dist/core/map-upsert.js.map +0 -1
  106. package/dist/core/module.d.ts.map +0 -1
  107. package/dist/core/module.js.map +0 -1
  108. package/dist/core/registry.d.ts.map +0 -1
  109. package/dist/core/registry.js.map +0 -1
  110. package/dist/core/tag.d.ts.map +0 -1
  111. package/dist/core/tag.js.map +0 -1
  112. package/dist/core/token.d.ts.map +0 -1
  113. package/dist/core/token.js.map +0 -1
  114. package/dist/core/types.d.ts.map +0 -1
  115. package/dist/core/types.js.map +0 -1
  116. package/dist/decorators/inject.d.ts.map +0 -1
  117. package/dist/decorators/inject.js.map +0 -1
  118. package/dist/decorators/injectable.d.ts.map +0 -1
  119. package/dist/decorators/injectable.js.map +0 -1
  120. package/dist/decorators/lifecycle-decorators.d.ts.map +0 -1
  121. package/dist/decorators/lifecycle-decorators.js.map +0 -1
  122. package/dist/errors/diagnostics.d.ts.map +0 -1
  123. package/dist/errors/diagnostics.js.map +0 -1
  124. package/dist/errors/errors.d.ts.map +0 -1
  125. package/dist/errors/errors.js.map +0 -1
  126. package/dist/index.d.ts.map +0 -1
  127. package/dist/index.js.map +0 -1
  128. package/dist/injection/descriptor.d.ts.map +0 -1
  129. package/dist/injection/descriptor.js.map +0 -1
  130. package/dist/injection/resolve-options.d.ts.map +0 -1
  131. package/dist/injection/resolve-options.js.map +0 -1
  132. package/dist/introspection/dependency-graph.d.ts.map +0 -1
  133. package/dist/introspection/dependency-graph.js.map +0 -1
  134. package/dist/introspection/graph-adapters/cytoscape.d.ts.map +0 -1
  135. package/dist/introspection/graph-adapters/cytoscape.js.map +0 -1
  136. package/dist/introspection/graph-adapters/dot.d.ts.map +0 -1
  137. package/dist/introspection/graph-adapters/dot.js.map +0 -1
  138. package/dist/introspection/graph-adapters/mermaid.d.ts.map +0 -1
  139. package/dist/introspection/graph-adapters/mermaid.js.map +0 -1
  140. package/dist/introspection/graph-adapters/reactflow.d.ts.map +0 -1
  141. package/dist/introspection/graph-adapters/reactflow.js.map +0 -1
  142. package/dist/introspection/inspector.d.ts.map +0 -1
  143. package/dist/introspection/inspector.js.map +0 -1
  144. package/dist/lifecycle/lifecycle-manager.d.ts.map +0 -1
  145. package/dist/lifecycle/lifecycle-manager.js.map +0 -1
  146. package/dist/lifecycle/scope-manager.d.ts.map +0 -1
  147. package/dist/lifecycle/scope-manager.js.map +0 -1
  148. package/dist/metadata/metadata-keys.d.ts.map +0 -1
  149. package/dist/metadata/metadata-keys.js.map +0 -1
  150. package/dist/metadata/metadata-reader-token.d.ts.map +0 -1
  151. package/dist/metadata/metadata-reader-token.js.map +0 -1
  152. package/dist/metadata/metadata-types.d.ts.map +0 -1
  153. package/dist/metadata/metadata-types.js.map +0 -1
  154. package/dist/metadata/symbol-metadata-reader.d.ts.map +0 -1
  155. package/dist/metadata/symbol-metadata-reader.js.map +0 -1
  156. package/dist/metadata/verifying-metadata-reader.d.ts.map +0 -1
  157. package/dist/metadata/verifying-metadata-reader.js.map +0 -1
  158. package/dist/resolution/cache/activation-need.d.ts.map +0 -1
  159. package/dist/resolution/cache/activation-need.js.map +0 -1
  160. package/dist/resolution/cache/binding-lookup-cache.d.ts.map +0 -1
  161. package/dist/resolution/cache/binding-lookup-cache.js.map +0 -1
  162. package/dist/resolution/cache/class-introspector.d.ts.map +0 -1
  163. package/dist/resolution/cache/class-introspector.js.map +0 -1
  164. package/dist/resolution/context.d.ts.map +0 -1
  165. package/dist/resolution/context.js.map +0 -1
  166. package/dist/resolution/path/resolution-path.d.ts.map +0 -1
  167. package/dist/resolution/path/resolution-path.js.map +0 -1
  168. package/dist/resolution/plan/instantiation-plan.d.ts.map +0 -1
  169. package/dist/resolution/plan/instantiation-plan.js.map +0 -1
  170. package/dist/resolution/resolver.d.ts.map +0 -1
  171. package/dist/resolution/resolver.js.map +0 -1
  172. package/dist/resolution/select/binding-select.d.ts.map +0 -1
  173. package/dist/resolution/select/binding-select.js.map +0 -1
  174. package/dist/resolution/select/constraints.d.ts.map +0 -1
  175. package/dist/resolution/select/constraints.js.map +0 -1
  176. package/src/ambient/active-container.ts +0 -69
  177. package/src/container/binding-builders.ts +0 -332
  178. package/src/container/container.ts +0 -973
  179. package/src/core/binding-scope.ts +0 -15
  180. package/src/core/binding.ts +0 -477
  181. package/src/core/constraint-requirement.ts +0 -94
  182. package/src/core/constructor-type.ts +0 -18
  183. package/src/core/map-upsert.ts +0 -53
  184. package/src/core/module.ts +0 -117
  185. package/src/core/registry.ts +0 -371
  186. package/src/core/tag.ts +0 -158
  187. package/src/core/token.ts +0 -31
  188. package/src/core/types.ts +0 -149
  189. package/src/decorators/inject.ts +0 -101
  190. package/src/decorators/injectable.ts +0 -134
  191. package/src/decorators/lifecycle-decorators.ts +0 -43
  192. package/src/errors/diagnostics.ts +0 -45
  193. package/src/errors/errors.ts +0 -476
  194. package/src/index.ts +0 -139
  195. package/src/injection/descriptor.ts +0 -218
  196. package/src/injection/resolve-options.ts +0 -144
  197. package/src/introspection/dependency-graph.ts +0 -282
  198. package/src/introspection/graph-adapters/cytoscape.ts +0 -78
  199. package/src/introspection/graph-adapters/dot.ts +0 -32
  200. package/src/introspection/graph-adapters/mermaid.ts +0 -61
  201. package/src/introspection/graph-adapters/reactflow.ts +0 -84
  202. package/src/introspection/inspector.ts +0 -134
  203. package/src/lifecycle/lifecycle-manager.ts +0 -272
  204. package/src/lifecycle/scope-manager.ts +0 -158
  205. package/src/metadata/metadata-keys.ts +0 -28
  206. package/src/metadata/metadata-reader-token.ts +0 -10
  207. package/src/metadata/metadata-types.ts +0 -57
  208. package/src/metadata/symbol-metadata-reader.ts +0 -126
  209. package/src/metadata/verifying-metadata-reader.ts +0 -41
  210. package/src/resolution/cache/activation-need.ts +0 -87
  211. package/src/resolution/cache/binding-lookup-cache.ts +0 -209
  212. package/src/resolution/cache/class-introspector.ts +0 -256
  213. package/src/resolution/context.ts +0 -331
  214. package/src/resolution/path/resolution-path.ts +0 -167
  215. package/src/resolution/plan/instantiation-plan.ts +0 -617
  216. package/src/resolution/resolver.ts +0 -1675
  217. package/src/resolution/select/binding-select.ts +0 -210
  218. package/src/resolution/select/constraints.ts +0 -146
@@ -1,210 +0,0 @@
1
- import type { Binding, BindingSlot } from "#/core/binding";
2
- import type { BindingTag, TagKeyMask } from "#/core/tag";
3
- import { coversTagKeys, NO_TAG_KEYS } from "#/core/tag";
4
- import type { ConstraintContext, ResolveOptions } from "#/core/types";
5
- import { AmbiguousBindingError } from "#/errors/errors";
6
-
7
- /**
8
- * Selects a single candidate from a list of bindings using slot matching + predicates.
9
- * Returns undefined if no match, throws AmbiguousBindingError if multiple match.
10
- *
11
- * @since 0.3.16-canary.0
12
- */
13
- export function selectBinding(
14
- bindings: ReadonlyArray<Binding>,
15
- options: ResolveOptions | undefined,
16
- ctx: ConstraintContext,
17
- tokenDisplayName: string,
18
- ): Binding | undefined {
19
- const candidates = filterBindings(bindings, options, ctx, true);
20
- if (candidates.length === 0) {
21
- return undefined;
22
- }
23
- if (candidates.length === 1) {
24
- return candidates[0];
25
- }
26
- // Most specific wins, predicate before tag count: a lone predicate-carrying candidate beats
27
- // predicate-less ones, a predicate being a deliberate specialization of the default. This order is
28
- // what keeps every resolution that already succeeds deciding the same way.
29
- let predicatedCandidate: Binding | undefined;
30
- for (const candidate of candidates) {
31
- if (candidate.predicate !== undefined) {
32
- if (predicatedCandidate !== undefined) {
33
- predicatedCandidate = undefined;
34
- break;
35
- }
36
- predicatedCandidate = candidate;
37
- }
38
- }
39
- if (predicatedCandidate !== undefined) {
40
- return predicatedCandidate;
41
- }
42
- // Reached only where the throw was: a slot declaring more of what the request carries is the more
43
- // specific match, so an over-specified request resolves instead of being ambiguous.
44
- const mostSpecific = mostSpecificByTagCount(candidates);
45
- if (mostSpecific !== undefined) {
46
- return mostSpecific;
47
- }
48
- throw new AmbiguousBindingError(
49
- tokenDisplayName,
50
- candidates.map((c) => c.id),
51
- );
52
- }
53
-
54
- /** The lone candidate declaring more tags than every other, or `undefined` when that is a tie. */
55
- function mostSpecificByTagCount(candidates: ReadonlyArray<Binding>): Binding | undefined {
56
- let best: Binding | undefined;
57
- let bestCount = -1;
58
- let tied = false;
59
- for (const candidate of candidates) {
60
- const count = candidate.slot.tags.length;
61
- if (count > bestCount) {
62
- best = candidate;
63
- bestCount = count;
64
- tied = false;
65
- } else if (count === bestCount) {
66
- tied = true;
67
- }
68
- }
69
- return tied ? undefined : best;
70
- }
71
-
72
- /**
73
- * Selects all candidates matching options + predicates.
74
- *
75
- * @since 0.3.16-canary.0
76
- */
77
- export function selectAllBindings(
78
- bindings: ReadonlyArray<Binding>,
79
- options: ResolveOptions | undefined,
80
- ctx: ConstraintContext,
81
- ): Array<Binding> {
82
- // `resolveAll` matches the slot only when the request carries a criterion; with none it takes
83
- // every binding, where `resolve` would read an absent criterion as "the default slot".
84
- return filterBindings(bindings, options, ctx, options !== undefined && hasSlotCriterion(options));
85
- }
86
-
87
- /**
88
- * @param bindings - the token's candidates, in registration order
89
- * @param options - the request's selection criteria, if any
90
- * @param ctx - what the constraint predicates read
91
- * @param requiresSlotMatch - `resolve` always matches the slot, where an absent criterion means
92
- * "the default slot"; `resolveAll` matches only when the request carries one
93
- */
94
- function filterBindings(
95
- bindings: ReadonlyArray<Binding>,
96
- options: ResolveOptions | undefined,
97
- ctx: ConstraintContext,
98
- requiresSlotMatch: boolean,
99
- ): Array<Binding> {
100
- const result: Array<Binding> = [];
101
- // A predicate is user code that may rebind the token mid-walk, but the registry replaces a
102
- // token's list on mutation instead of splicing it, so this walk keeps its own list — no copy.
103
- for (let index = 0; index < bindings.length; index += 1) {
104
- const binding = bindings[index]!;
105
- if (requiresSlotMatch && !matchesSlot(binding.slot, options)) {
106
- continue;
107
- }
108
- const predicate = binding.predicate;
109
- if (predicate === undefined) {
110
- result.push(binding);
111
- continue;
112
- }
113
- if (predicate(ctx)) {
114
- result.push(binding);
115
- }
116
- }
117
- return result;
118
- }
119
-
120
- function hasSlotCriterion(options: ResolveOptions): boolean {
121
- return options.name !== undefined || requestedTagKeyMask(options) !== NO_TAG_KEYS;
122
- }
123
-
124
- /**
125
- * Whether a binding's slot satisfies a request: names must be equal, and every tag the slot
126
- * declares must be among the tags requested.
127
- *
128
- * @remarks The tag half is a key-mask subset test before any criterion is read, so a slot the
129
- * request cannot satisfy is rejected in one word compare. Criteria are interned, so what follows is
130
- * identity.
131
- *
132
- * @since 0.5.0-canary.9
133
- */
134
- export function matchesSlot(slot: BindingSlot, options: ResolveOptions | undefined): boolean {
135
- const requestedName = options?.name;
136
-
137
- if (slot.name !== undefined) {
138
- if (slot.name !== requestedName) {
139
- return false;
140
- }
141
- } else if (requestedName !== undefined) {
142
- return false;
143
- }
144
-
145
- const slotMask = slot.keyMask;
146
- const requestMask = requestedTagKeyMask(options);
147
-
148
- if (slotMask === NO_TAG_KEYS) {
149
- // A request carrying tags needs a tagged slot: an untagged binding never matches.
150
- return requestMask === NO_TAG_KEYS;
151
- }
152
- if (!coversTagKeys(requestMask, slotMask)) {
153
- return false;
154
- }
155
-
156
- // The mask can collide two keys onto one bit, so the exact criteria still have to be confirmed.
157
- const slotTags = slot.tags;
158
-
159
- for (let index = 0; index < slotTags.length; index += 1) {
160
- if (!requestCarries(options, slotTags[index]!)) {
161
- return false;
162
- }
163
- }
164
-
165
- return true;
166
- }
167
-
168
- /**
169
- * The key set a request covers, across both spellings the shorthand folds into one.
170
- *
171
- * @since 0.6.0
172
- */
173
- export function requestedTagKeyMask(options: ResolveOptions | undefined): TagKeyMask {
174
- if (options === undefined) {
175
- return NO_TAG_KEYS;
176
- }
177
- const single = options.tag;
178
- const listed = options.tags;
179
- let mask = single === undefined ? NO_TAG_KEYS : single.mask;
180
-
181
- if (listed !== undefined) {
182
- for (let index = 0; index < listed.length; index += 1) {
183
- mask = (mask | listed[index]!.mask) as TagKeyMask;
184
- }
185
- }
186
-
187
- return mask;
188
- }
189
-
190
- /** Whether a request names this exact criterion — identity, because criteria are interned. */
191
- function requestCarries(options: ResolveOptions | undefined, criterion: BindingTag): boolean {
192
- if (options === undefined) {
193
- return false;
194
- }
195
- if (options.tag === criterion) {
196
- return true;
197
- }
198
- const listed = options.tags;
199
-
200
- if (listed === undefined) {
201
- return false;
202
- }
203
- for (let index = 0; index < listed.length; index += 1) {
204
- if (listed[index] === criterion) {
205
- return true;
206
- }
207
- }
208
-
209
- return false;
210
- }
@@ -1,146 +0,0 @@
1
- import { requiringAncestorSlotName } from "#/core/constraint-requirement";
2
- import type { BindingTag } from "#/core/tag";
3
- import { coversTagKeys, tagKeyMaskOf } from "#/core/tag";
4
- import type { Token } from "#/core/token";
5
- import { tokenName } from "#/core/token";
6
- import type { BindingConstraint, Constructor } from "#/core/types";
7
- import { EmptyTagCriteriaError } from "#/errors/errors";
8
-
9
- /**
10
- * Matches when the direct parent frame resolves the given token.
11
- *
12
- * @since 0.3.16-canary.0
13
- */
14
- export function whenParentIs(token: Token<unknown> | Constructor): BindingConstraint {
15
- const tokenDisplayName = tokenName(token);
16
- return (constraintContext) =>
17
- constraintContext.parent !== undefined && constraintContext.parent.tokenName === tokenDisplayName;
18
- }
19
-
20
- /**
21
- * Matches when there is no direct parent frame, or it resolves a different token.
22
- *
23
- * @since 0.3.16-canary.0
24
- */
25
- export function whenNoParentIs(token: Token<unknown> | Constructor): BindingConstraint {
26
- const tokenDisplayName = tokenName(token);
27
- return (constraintContext) =>
28
- constraintContext.parent === undefined || constraintContext.parent.tokenName !== tokenDisplayName;
29
- }
30
-
31
- /**
32
- * Matches when at least one ancestor frame resolves the given token.
33
- *
34
- * @since 0.3.16-canary.0
35
- */
36
- export function whenAnyAncestorIs(token: Token<unknown> | Constructor): BindingConstraint {
37
- const tokenDisplayName = tokenName(token);
38
- return (constraintContext) =>
39
- constraintContext.ancestors.some((ancestorFrame) => ancestorFrame.tokenName === tokenDisplayName);
40
- }
41
-
42
- /**
43
- * Matches when no ancestor frame resolves the given token.
44
- *
45
- * @since 0.3.16-canary.0
46
- */
47
- export function whenNoAncestorIs(token: Token<unknown> | Constructor): BindingConstraint {
48
- const tokenDisplayName = tokenName(token);
49
- return (constraintContext) =>
50
- constraintContext.ancestors.every((ancestorFrame) => ancestorFrame.tokenName !== tokenDisplayName);
51
- }
52
-
53
- /**
54
- * Matches when the direct parent slot carries the given name.
55
- *
56
- * @since 0.3.16-canary.0
57
- */
58
- export function whenParentNamed(name: string): BindingConstraint {
59
- return requiringAncestorSlotName(
60
- (constraintContext) => constraintContext.parent !== undefined && constraintContext.parent.slot.name === name,
61
- name,
62
- "whenParentNamed",
63
- );
64
- }
65
-
66
- /**
67
- * Matches when at least one ancestor slot carries the given name.
68
- *
69
- * @since 0.3.16-canary.0
70
- */
71
- export function whenAnyAncestorNamed(name: string): BindingConstraint {
72
- return requiringAncestorSlotName(
73
- (constraintContext) => constraintContext.ancestors.some((ancestorFrame) => ancestorFrame.slot.name === name),
74
- name,
75
- "whenAnyAncestorNamed",
76
- );
77
- }
78
-
79
- /**
80
- * Matches when the direct parent slot carries the given tag pair.
81
- *
82
- * @since 0.3.16-canary.0
83
- */
84
- export function whenParentTagged(criterion: BindingTag): BindingConstraint {
85
- return (constraintContext) =>
86
- constraintContext.parent !== undefined && constraintContext.parent.slot.tags.includes(criterion);
87
- }
88
-
89
- /**
90
- * Matches when at least one ancestor slot carries the given tag pair.
91
- *
92
- * @since 0.3.16-canary.0
93
- */
94
- export function whenAnyAncestorTagged(criterion: BindingTag): BindingConstraint {
95
- return (constraintContext) =>
96
- constraintContext.ancestors.some((ancestorFrame) => ancestorFrame.slot.tags.includes(criterion));
97
- }
98
-
99
- /**
100
- * Matches when the direct parent slot carries **all** of the given tag pairs.
101
- * Equivalent to AND-composing multiple `whenParentTagged` calls but evaluates
102
- * in a single predicate invocation — no intermediate closure allocations.
103
- *
104
- * @since 0.3.16-canary.1
105
- */
106
- export function whenParentTaggedAll(tags: ReadonlyArray<BindingTag>): BindingConstraint {
107
- assertHasCriteria(tags, "whenParentTaggedAll");
108
- const wanted = tagKeyMaskOf(tags);
109
- return (constraintContext) => {
110
- const { parent } = constraintContext;
111
- if (parent === undefined || !coversTagKeys(parent.slot.keyMask, wanted)) {
112
- return false;
113
- }
114
- return tags.every((criterion) => parent.slot.tags.includes(criterion));
115
- };
116
- }
117
-
118
- /**
119
- * Matches when at least one ancestor slot carries **all** of the given tag pairs.
120
- * Equivalent to AND-composing multiple `whenAnyAncestorTagged` calls but evaluates
121
- * in a single predicate invocation — no intermediate closure allocations.
122
- *
123
- * @since 0.3.16-canary.1
124
- */
125
- export function whenAnyAncestorTaggedAll(tags: ReadonlyArray<BindingTag>): BindingConstraint {
126
- assertHasCriteria(tags, "whenAnyAncestorTaggedAll");
127
- const wanted = tagKeyMaskOf(tags);
128
- return (constraintContext) =>
129
- constraintContext.ancestors.some(
130
- (frame) =>
131
- coversTagKeys(frame.slot.keyMask, wanted) && tags.every((criterion) => frame.slot.tags.includes(criterion)),
132
- );
133
- }
134
-
135
- /**
136
- * Refuses a criteria list with nothing in it.
137
- *
138
- * @remarks "carries all of no criteria" is vacuously true, so an empty list quietly turns the
139
- * constraint into "has an ancestor at all" — a weaker predicate than the caller wrote, and one that
140
- * still wins specificity over an unconstrained binding.
141
- */
142
- function assertHasCriteria(tags: ReadonlyArray<BindingTag>, helperName: string): void {
143
- if (tags.length === 0) {
144
- throw new EmptyTagCriteriaError(helperName);
145
- }
146
- }