bunja 3.0.0-alpha.3 → 3.0.0-alpha.4

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/bunja.ts CHANGED
@@ -94,7 +94,6 @@ export type Dep<T> = Bunja<T, any> | Scope<T>;
94
94
 
95
95
  type AnyBunja = Bunja<any, any>;
96
96
  type ScopeInstanceMap = Map<Scope<unknown>, ScopeInstance>;
97
- type BunjaDependencyEdge = "required" | "optional";
98
97
 
99
98
  interface BunjaFrame {
100
99
  use: BunjaUseFn;
@@ -251,11 +250,8 @@ function getBoundScopeSet(
251
250
  function getScopeInstances(
252
251
  scopes: Scope<unknown>[],
253
252
  scopeInstanceMap: ScopeInstanceMap,
254
- excludeScopes: Set<Scope<unknown>> = new Set(),
255
253
  ): ScopeInstance[] {
256
- return scopes
257
- .filter((scope) => !excludeScopes.has(scope))
258
- .map((scope) => scopeInstanceMap.get(scope)!);
254
+ return scopes.map((scope) => scopeInstanceMap.get(scope)!);
259
255
  }
260
256
 
261
257
  function dedupeScopeInstances(
@@ -331,6 +327,7 @@ export class BunjaStore {
331
327
  readScope,
332
328
  new Set(),
333
329
  bunjaRef.seed,
330
+ true,
334
331
  );
335
332
  const result: BunjaStoreGetResult<T> = {
336
333
  value: resolved.value,
@@ -366,6 +363,7 @@ export class BunjaStore {
366
363
  readScope: ReadScope,
367
364
  inProgressBunjas: Set<AnyBunja>,
368
365
  seed: Seed = bunjaRef.bunja.defaultSeed,
366
+ includeBoundScopeDeps: boolean = false,
369
367
  ): ResolvedBunja<T> {
370
368
  const { bunja } = bunjaRef;
371
369
  if (inProgressBunjas.has(bunja)) {
@@ -382,6 +380,7 @@ export class BunjaStore {
382
380
  resolvedReadScope,
383
381
  inProgressBunjas,
384
382
  seed,
383
+ includeBoundScopeDeps,
385
384
  );
386
385
  }
387
386
  const scopeInstanceMap = this.#resolveScopeInstanceMap(
@@ -394,9 +393,10 @@ export class BunjaStore {
394
393
  scopeInstanceMap,
395
394
  );
396
395
  const directDeps = getScopeInstances(
397
- bunja.requiredScopes,
396
+ includeBoundScopeDeps
397
+ ? bunja.requiredScopes
398
+ : bunja.requiredScopes.filter((scope) => !boundScopes.has(scope)),
398
399
  scopeInstanceMap,
399
- boundScopes,
400
400
  );
401
401
  const baseId = bunja.calcBaseInstanceId(scopeInstanceMap);
402
402
  const bucket = this.#bunjaBuckets.get(baseId);
@@ -433,6 +433,7 @@ export class BunjaStore {
433
433
  resolvedReadScope,
434
434
  inProgressBunjas,
435
435
  seed,
436
+ includeBoundScopeDeps,
436
437
  scopeInstanceMap,
437
438
  );
438
439
  } finally {
@@ -444,6 +445,7 @@ export class BunjaStore {
444
445
  readScope: ReadScope,
445
446
  inProgressBunjas: Set<AnyBunja>,
446
447
  seed: Seed,
448
+ includeBoundScopeDeps: boolean,
447
449
  initialScopeInstanceMap: ScopeInstanceMap = new Map(),
448
450
  ): ResolvedBunja<T> {
449
451
  const { bunja } = bunjaRef;
@@ -475,9 +477,10 @@ export class BunjaStore {
475
477
  frame.scopeInstanceMap,
476
478
  );
477
479
  const directDeps = getScopeInstances(
478
- bunja.requiredScopes,
480
+ includeBoundScopeDeps
481
+ ? bunja.requiredScopes
482
+ : bunja.requiredScopes.filter((scope) => !boundScopes.has(scope)),
479
483
  frame.scopeInstanceMap,
480
- boundScopes,
481
484
  );
482
485
  const baseId = bunja.calcBaseInstanceId(frame.scopeInstanceMap);
483
486
  const id = bunja.calcInstanceId(
@@ -560,11 +563,10 @@ export class BunjaStore {
560
563
  return this.#useScopeInFrame(frame, dep as Scope<unknown>);
561
564
  }
562
565
  if (dep instanceof Bunja || isBunjaRef(dep)) {
563
- return this.#useBunjaDependencyInFrame(
564
- frame,
565
- normalizeBunjaRuntimeRef(dep, scopeValuePairs),
566
- "required",
567
- );
566
+ const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
567
+ const graphRef = toBunjaGraphRef(bunjaRef);
568
+ currentBunja.addRequiredBunjaRef(graphRef);
569
+ return this.#useBunjaDependencyInFrame(frame, bunjaRef);
568
570
  }
569
571
  throw new Error("`bunja.use` can only be used with Bunja or Scope.");
570
572
  }) as BunjaUseFn,
@@ -573,18 +575,15 @@ export class BunjaStore {
573
575
  throw new Error("`bunja.will` can only be used with Bunja.");
574
576
  }
575
577
  const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
576
- currentBunja.addOptionalBunjaRef(toBunjaGraphRef(bunjaRef));
578
+ const graphRef = toBunjaGraphRef(bunjaRef);
579
+ currentBunja.addOptionalBunjaRef(graphRef);
577
580
  return () => {
578
581
  if (frameStack[frameStack.length - 1] !== frame) {
579
582
  throw new Error(
580
583
  "A thunk returned by `bunja.will` can only be called inside the same bunja init function.",
581
584
  );
582
585
  }
583
- return this.#useBunjaDependencyInFrame(
584
- frame,
585
- bunjaRef,
586
- "optional",
587
- );
586
+ return this.#useBunjaDependencyInFrame(frame, bunjaRef);
588
587
  };
589
588
  }) as BunjaWillFn,
590
589
  effect: ((callback: BunjaEffectCallback) => {
@@ -615,14 +614,8 @@ export class BunjaStore {
615
614
  #useBunjaDependencyInFrame<T, Seed>(
616
615
  frame: BunjaInitFrame,
617
616
  bunjaRef: NormalizedBunjaRuntimeRef<T, Seed>,
618
- edge: BunjaDependencyEdge,
619
617
  ): T {
620
618
  const graphRef = toBunjaGraphRef(bunjaRef);
621
- if (edge === "optional" || graphRef.scopeValuePairs.length > 0) {
622
- frame.currentBunja.addOptionalBunjaRef(graphRef);
623
- } else if (edge === "required") {
624
- frame.currentBunja.addRequiredBunjaRef(graphRef);
625
- }
626
619
  const resolved = this.#resolveBunjaRef(
627
620
  graphRef,
628
621
  frame.readScope,
@@ -725,11 +718,14 @@ export class BunjaStore {
725
718
  return readScope(dep as Scope<unknown>);
726
719
  }
727
720
  if (dep instanceof Bunja || isBunjaRef(dep)) {
728
- const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
729
- return this.#prebakeBunjaDependencyInFrame(
730
- frame,
731
- toBunjaGraphRef(bunjaRef),
732
- "required",
721
+ const bunjaRef = toBunjaGraphRef(
722
+ normalizeBunjaRuntimeRef(dep, scopeValuePairs),
723
+ );
724
+ currentBunja.addRequiredBunjaRef(bunjaRef);
725
+ return this.#prebakeBunjaRef(
726
+ bunjaRef,
727
+ readScope,
728
+ prebakeContext,
733
729
  );
734
730
  }
735
731
  throw new Error("`bunja.use` can only be used with Bunja or Scope.");
@@ -760,22 +756,6 @@ export class BunjaStore {
760
756
  } satisfies BunjaPrebakeFrame;
761
757
  return frame;
762
758
  }
763
- #prebakeBunjaDependencyInFrame<T, Seed>(
764
- frame: BunjaPrebakeFrame,
765
- bunjaRef: NormalizedBunjaRef<T, Seed>,
766
- edge: BunjaDependencyEdge,
767
- ): T {
768
- if (edge === "optional" || bunjaRef.scopeValuePairs.length > 0) {
769
- frame.currentBunja.addOptionalBunjaRef(bunjaRef);
770
- } else if (edge === "required") {
771
- frame.currentBunja.addRequiredBunjaRef(bunjaRef);
772
- }
773
- return this.#prebakeBunjaRef(
774
- bunjaRef,
775
- frame.readScope,
776
- frame.prebakeContext,
777
- );
778
- }
779
759
  #resolveScopeInstanceMap(
780
760
  bunja: AnyBunja,
781
761
  readScope: ReadScope,
@@ -984,8 +964,11 @@ export class Bunja<T, Seed = NoSeed> {
984
964
  const requiredBunjas = this.requiredBunjas;
985
965
  const expandedRequiredBunjas = toposortRequiredBunjas(requiredBunjas);
986
966
  const requiredScopeSet = new Set<Scope<unknown>>();
987
- for (const bunja of expandedRequiredBunjas) {
988
- for (const scope of bunja.requiredScopes) requiredScopeSet.add(scope);
967
+ for (const ref of requiredBunjaRefs) {
968
+ const boundScopes = getBoundScopeSet(ref.scopeValuePairs);
969
+ for (const scope of ref.bunja.requiredScopes) {
970
+ if (!boundScopes.has(scope)) requiredScopeSet.add(scope);
971
+ }
989
972
  }
990
973
  for (const scope of scopes) requiredScopeSet.add(scope);
991
974
  const requiredScopes = Array.from(requiredScopeSet);
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@disjukr/bunja",
3
- "version": "3.0.0-alpha.3",
3
+ "version": "3.0.0-alpha.4",
4
4
  "license": "Zlib",
5
5
  "exports": {
6
6
  ".": "./bunja.ts",
@@ -73,8 +73,8 @@ function isBunjaRef(value) {
73
73
  function getBoundScopeSet(scopeValuePairs) {
74
74
  return new Set(scopeValuePairs.map(([scope]) => scope));
75
75
  }
76
- function getScopeInstances(scopes, scopeInstanceMap, excludeScopes = /* @__PURE__ */ new Set()) {
77
- return scopes.filter((scope) => !excludeScopes.has(scope)).map((scope) => scopeInstanceMap.get(scope));
76
+ function getScopeInstances(scopes, scopeInstanceMap) {
77
+ return scopes.map((scope) => scopeInstanceMap.get(scope));
78
78
  }
79
79
  function dedupeScopeInstances(scopeInstances) {
80
80
  const seen = /* @__PURE__ */ new Set();
@@ -127,7 +127,7 @@ var BunjaStore = class BunjaStore {
127
127
  }
128
128
  get(bunjaOrRef, readScope) {
129
129
  const bunjaRef = normalizeBunjaRuntimeRef(bunjaOrRef);
130
- const resolved = this.#resolveBunjaRef(toBunjaGraphRef(bunjaRef), readScope, /* @__PURE__ */ new Set(), bunjaRef.seed);
130
+ const resolved = this.#resolveBunjaRef(toBunjaGraphRef(bunjaRef), readScope, /* @__PURE__ */ new Set(), bunjaRef.seed, true);
131
131
  const result = {
132
132
  value: resolved.value,
133
133
  mount: resolved.mount,
@@ -150,17 +150,17 @@ var BunjaStore = class BunjaStore {
150
150
  requiredScopes: bunjaRef.bunja.requiredScopes
151
151
  };
152
152
  }
153
- #resolveBunjaRef(bunjaRef, readScope, inProgressBunjas, seed = bunjaRef.bunja.defaultSeed) {
153
+ #resolveBunjaRef(bunjaRef, readScope, inProgressBunjas, seed = bunjaRef.bunja.defaultSeed, includeBoundScopeDeps = false) {
154
154
  const { bunja: bunja$1 } = bunjaRef;
155
155
  if (inProgressBunjas.has(bunja$1)) throw new Error("Circular bunja dependency detected.");
156
156
  const resolvedReadScope = bunjaRef.scopeValuePairs.length > 0 ? createReadScopeFn(bunjaRef.scopeValuePairs, readScope) : readScope;
157
157
  inProgressBunjas.add(bunja$1);
158
158
  try {
159
- if (!bunja$1.baked) return this.#createResolvedBunja(bunjaRef, resolvedReadScope, inProgressBunjas, seed);
159
+ if (!bunja$1.baked) return this.#createResolvedBunja(bunjaRef, resolvedReadScope, inProgressBunjas, seed, includeBoundScopeDeps);
160
160
  const scopeInstanceMap = this.#resolveScopeInstanceMap(bunja$1, resolvedReadScope);
161
161
  const boundScopes = getBoundScopeSet(bunjaRef.scopeValuePairs);
162
162
  const scopeInstances = getScopeInstances(bunja$1.requiredScopes, scopeInstanceMap);
163
- const directDeps = getScopeInstances(bunja$1.requiredScopes, scopeInstanceMap, boundScopes);
163
+ const directDeps = getScopeInstances(includeBoundScopeDeps ? bunja$1.requiredScopes : bunja$1.requiredScopes.filter((scope) => !boundScopes.has(scope)), scopeInstanceMap);
164
164
  const baseId = bunja$1.calcBaseInstanceId(scopeInstanceMap);
165
165
  const bucket = this.#bunjaBuckets.get(baseId);
166
166
  if (bucket) for (const candidateId of Array.from(bucket)) {
@@ -175,12 +175,12 @@ var BunjaStore = class BunjaStore {
175
175
  if (!instance) continue;
176
176
  return this.#toResolvedBunja(instance, scopeInstances, directDeps, activeDeps.deps);
177
177
  }
178
- return this.#createResolvedBunja(bunjaRef, resolvedReadScope, inProgressBunjas, seed, scopeInstanceMap);
178
+ return this.#createResolvedBunja(bunjaRef, resolvedReadScope, inProgressBunjas, seed, includeBoundScopeDeps, scopeInstanceMap);
179
179
  } finally {
180
180
  inProgressBunjas.delete(bunja$1);
181
181
  }
182
182
  }
183
- #createResolvedBunja(bunjaRef, readScope, inProgressBunjas, seed, initialScopeInstanceMap = /* @__PURE__ */ new Map()) {
183
+ #createResolvedBunja(bunjaRef, readScope, inProgressBunjas, seed, includeBoundScopeDeps, initialScopeInstanceMap = /* @__PURE__ */ new Map()) {
184
184
  const { bunja: bunja$1 } = bunjaRef;
185
185
  return this.wrapInstance((dispose) => {
186
186
  let instanceCreated = false;
@@ -197,7 +197,7 @@ var BunjaStore = class BunjaStore {
197
197
  this.#ensureRequiredScopeInstances(bunja$1, frame.scopeInstanceMap, readScope);
198
198
  const boundScopes = getBoundScopeSet(bunjaRef.scopeValuePairs);
199
199
  const scopeInstances = getScopeInstances(bunja$1.requiredScopes, frame.scopeInstanceMap);
200
- const directDeps = getScopeInstances(bunja$1.requiredScopes, frame.scopeInstanceMap, boundScopes);
200
+ const directDeps = getScopeInstances(includeBoundScopeDeps ? bunja$1.requiredScopes : bunja$1.requiredScopes.filter((scope) => !boundScopes.has(scope)), frame.scopeInstanceMap);
201
201
  const baseId = bunja$1.calcBaseInstanceId(frame.scopeInstanceMap);
202
202
  const id = bunja$1.calcInstanceId(frame.scopeInstanceMap, frame.activeDependencyIds);
203
203
  const existing = this.#bunjas[id];
@@ -242,16 +242,22 @@ var BunjaStore = class BunjaStore {
242
242
  activeDependencyDeps: [],
243
243
  use: ((dep, scopeValuePairs) => {
244
244
  if (dep instanceof Scope) return this.#useScopeInFrame(frame, dep);
245
- if (dep instanceof Bunja || isBunjaRef(dep)) return this.#useBunjaDependencyInFrame(frame, normalizeBunjaRuntimeRef(dep, scopeValuePairs), "required");
245
+ if (dep instanceof Bunja || isBunjaRef(dep)) {
246
+ const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
247
+ const graphRef = toBunjaGraphRef(bunjaRef);
248
+ currentBunja.addRequiredBunjaRef(graphRef);
249
+ return this.#useBunjaDependencyInFrame(frame, bunjaRef);
250
+ }
246
251
  throw new Error("`bunja.use` can only be used with Bunja or Scope.");
247
252
  }),
248
253
  will: ((dep, scopeValuePairs) => {
249
254
  if (!(dep instanceof Bunja || isBunjaRef(dep))) throw new Error("`bunja.will` can only be used with Bunja.");
250
255
  const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
251
- currentBunja.addOptionalBunjaRef(toBunjaGraphRef(bunjaRef));
256
+ const graphRef = toBunjaGraphRef(bunjaRef);
257
+ currentBunja.addOptionalBunjaRef(graphRef);
252
258
  return () => {
253
259
  if (frameStack[frameStack.length - 1] !== frame) throw new Error("A thunk returned by `bunja.will` can only be called inside the same bunja init function.");
254
- return this.#useBunjaDependencyInFrame(frame, bunjaRef, "optional");
260
+ return this.#useBunjaDependencyInFrame(frame, bunjaRef);
255
261
  };
256
262
  }),
257
263
  effect: ((callback) => {
@@ -270,10 +276,8 @@ var BunjaStore = class BunjaStore {
270
276
  }
271
277
  return scopeInstance.value;
272
278
  }
273
- #useBunjaDependencyInFrame(frame, bunjaRef, edge) {
279
+ #useBunjaDependencyInFrame(frame, bunjaRef) {
274
280
  const graphRef = toBunjaGraphRef(bunjaRef);
275
- if (edge === "optional" || graphRef.scopeValuePairs.length > 0) frame.currentBunja.addOptionalBunjaRef(graphRef);
276
- else if (edge === "required") frame.currentBunja.addRequiredBunjaRef(graphRef);
277
281
  const resolved = this.#resolveBunjaRef(graphRef, frame.readScope, frame.inProgressBunjas, bunjaRef.seed);
278
282
  frame.activeDependencyIds.add(resolved.instance.id);
279
283
  frame.activeDependencyRecipes.push({
@@ -331,8 +335,9 @@ var BunjaStore = class BunjaStore {
331
335
  return readScope(dep);
332
336
  }
333
337
  if (dep instanceof Bunja || isBunjaRef(dep)) {
334
- const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
335
- return this.#prebakeBunjaDependencyInFrame(frame, toBunjaGraphRef(bunjaRef), "required");
338
+ const bunjaRef = toBunjaGraphRef(normalizeBunjaRuntimeRef(dep, scopeValuePairs));
339
+ currentBunja.addRequiredBunjaRef(bunjaRef);
340
+ return this.#prebakeBunjaRef(bunjaRef, readScope, prebakeContext);
336
341
  }
337
342
  throw new Error("`bunja.use` can only be used with Bunja or Scope.");
338
343
  }),
@@ -350,11 +355,6 @@ var BunjaStore = class BunjaStore {
350
355
  };
351
356
  return frame;
352
357
  }
353
- #prebakeBunjaDependencyInFrame(frame, bunjaRef, edge) {
354
- if (edge === "optional" || bunjaRef.scopeValuePairs.length > 0) frame.currentBunja.addOptionalBunjaRef(bunjaRef);
355
- else if (edge === "required") frame.currentBunja.addRequiredBunjaRef(bunjaRef);
356
- return this.#prebakeBunjaRef(bunjaRef, frame.readScope, frame.prebakeContext);
357
- }
358
358
  #resolveScopeInstanceMap(bunja$1, readScope) {
359
359
  const scopeInstanceMap = /* @__PURE__ */ new Map();
360
360
  this.#ensureRequiredScopeInstances(bunja$1, scopeInstanceMap, readScope);
@@ -485,7 +485,10 @@ var Bunja = class Bunja {
485
485
  const requiredBunjas = this.requiredBunjas;
486
486
  const expandedRequiredBunjas = toposortRequiredBunjas(requiredBunjas);
487
487
  const requiredScopeSet = /* @__PURE__ */ new Set();
488
- for (const bunja$1 of expandedRequiredBunjas) for (const scope of bunja$1.requiredScopes) requiredScopeSet.add(scope);
488
+ for (const ref of requiredBunjaRefs) {
489
+ const boundScopes = getBoundScopeSet(ref.scopeValuePairs);
490
+ for (const scope of ref.bunja.requiredScopes) if (!boundScopes.has(scope)) requiredScopeSet.add(scope);
491
+ }
489
492
  for (const scope of scopes) requiredScopeSet.add(scope);
490
493
  this.#phase = {
491
494
  baked: true,
@@ -72,8 +72,8 @@ function isBunjaRef(value) {
72
72
  function getBoundScopeSet(scopeValuePairs) {
73
73
  return new Set(scopeValuePairs.map(([scope]) => scope));
74
74
  }
75
- function getScopeInstances(scopes, scopeInstanceMap, excludeScopes = /* @__PURE__ */ new Set()) {
76
- return scopes.filter((scope) => !excludeScopes.has(scope)).map((scope) => scopeInstanceMap.get(scope));
75
+ function getScopeInstances(scopes, scopeInstanceMap) {
76
+ return scopes.map((scope) => scopeInstanceMap.get(scope));
77
77
  }
78
78
  function dedupeScopeInstances(scopeInstances) {
79
79
  const seen = /* @__PURE__ */ new Set();
@@ -126,7 +126,7 @@ var BunjaStore = class BunjaStore {
126
126
  }
127
127
  get(bunjaOrRef, readScope) {
128
128
  const bunjaRef = normalizeBunjaRuntimeRef(bunjaOrRef);
129
- const resolved = this.#resolveBunjaRef(toBunjaGraphRef(bunjaRef), readScope, /* @__PURE__ */ new Set(), bunjaRef.seed);
129
+ const resolved = this.#resolveBunjaRef(toBunjaGraphRef(bunjaRef), readScope, /* @__PURE__ */ new Set(), bunjaRef.seed, true);
130
130
  const result = {
131
131
  value: resolved.value,
132
132
  mount: resolved.mount,
@@ -149,17 +149,17 @@ var BunjaStore = class BunjaStore {
149
149
  requiredScopes: bunjaRef.bunja.requiredScopes
150
150
  };
151
151
  }
152
- #resolveBunjaRef(bunjaRef, readScope, inProgressBunjas, seed = bunjaRef.bunja.defaultSeed) {
152
+ #resolveBunjaRef(bunjaRef, readScope, inProgressBunjas, seed = bunjaRef.bunja.defaultSeed, includeBoundScopeDeps = false) {
153
153
  const { bunja: bunja$1 } = bunjaRef;
154
154
  if (inProgressBunjas.has(bunja$1)) throw new Error("Circular bunja dependency detected.");
155
155
  const resolvedReadScope = bunjaRef.scopeValuePairs.length > 0 ? createReadScopeFn(bunjaRef.scopeValuePairs, readScope) : readScope;
156
156
  inProgressBunjas.add(bunja$1);
157
157
  try {
158
- if (!bunja$1.baked) return this.#createResolvedBunja(bunjaRef, resolvedReadScope, inProgressBunjas, seed);
158
+ if (!bunja$1.baked) return this.#createResolvedBunja(bunjaRef, resolvedReadScope, inProgressBunjas, seed, includeBoundScopeDeps);
159
159
  const scopeInstanceMap = this.#resolveScopeInstanceMap(bunja$1, resolvedReadScope);
160
160
  const boundScopes = getBoundScopeSet(bunjaRef.scopeValuePairs);
161
161
  const scopeInstances = getScopeInstances(bunja$1.requiredScopes, scopeInstanceMap);
162
- const directDeps = getScopeInstances(bunja$1.requiredScopes, scopeInstanceMap, boundScopes);
162
+ const directDeps = getScopeInstances(includeBoundScopeDeps ? bunja$1.requiredScopes : bunja$1.requiredScopes.filter((scope) => !boundScopes.has(scope)), scopeInstanceMap);
163
163
  const baseId = bunja$1.calcBaseInstanceId(scopeInstanceMap);
164
164
  const bucket = this.#bunjaBuckets.get(baseId);
165
165
  if (bucket) for (const candidateId of Array.from(bucket)) {
@@ -174,12 +174,12 @@ var BunjaStore = class BunjaStore {
174
174
  if (!instance) continue;
175
175
  return this.#toResolvedBunja(instance, scopeInstances, directDeps, activeDeps.deps);
176
176
  }
177
- return this.#createResolvedBunja(bunjaRef, resolvedReadScope, inProgressBunjas, seed, scopeInstanceMap);
177
+ return this.#createResolvedBunja(bunjaRef, resolvedReadScope, inProgressBunjas, seed, includeBoundScopeDeps, scopeInstanceMap);
178
178
  } finally {
179
179
  inProgressBunjas.delete(bunja$1);
180
180
  }
181
181
  }
182
- #createResolvedBunja(bunjaRef, readScope, inProgressBunjas, seed, initialScopeInstanceMap = /* @__PURE__ */ new Map()) {
182
+ #createResolvedBunja(bunjaRef, readScope, inProgressBunjas, seed, includeBoundScopeDeps, initialScopeInstanceMap = /* @__PURE__ */ new Map()) {
183
183
  const { bunja: bunja$1 } = bunjaRef;
184
184
  return this.wrapInstance((dispose) => {
185
185
  let instanceCreated = false;
@@ -196,7 +196,7 @@ var BunjaStore = class BunjaStore {
196
196
  this.#ensureRequiredScopeInstances(bunja$1, frame.scopeInstanceMap, readScope);
197
197
  const boundScopes = getBoundScopeSet(bunjaRef.scopeValuePairs);
198
198
  const scopeInstances = getScopeInstances(bunja$1.requiredScopes, frame.scopeInstanceMap);
199
- const directDeps = getScopeInstances(bunja$1.requiredScopes, frame.scopeInstanceMap, boundScopes);
199
+ const directDeps = getScopeInstances(includeBoundScopeDeps ? bunja$1.requiredScopes : bunja$1.requiredScopes.filter((scope) => !boundScopes.has(scope)), frame.scopeInstanceMap);
200
200
  const baseId = bunja$1.calcBaseInstanceId(frame.scopeInstanceMap);
201
201
  const id = bunja$1.calcInstanceId(frame.scopeInstanceMap, frame.activeDependencyIds);
202
202
  const existing = this.#bunjas[id];
@@ -241,16 +241,22 @@ var BunjaStore = class BunjaStore {
241
241
  activeDependencyDeps: [],
242
242
  use: ((dep, scopeValuePairs) => {
243
243
  if (dep instanceof Scope) return this.#useScopeInFrame(frame, dep);
244
- if (dep instanceof Bunja || isBunjaRef(dep)) return this.#useBunjaDependencyInFrame(frame, normalizeBunjaRuntimeRef(dep, scopeValuePairs), "required");
244
+ if (dep instanceof Bunja || isBunjaRef(dep)) {
245
+ const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
246
+ const graphRef = toBunjaGraphRef(bunjaRef);
247
+ currentBunja.addRequiredBunjaRef(graphRef);
248
+ return this.#useBunjaDependencyInFrame(frame, bunjaRef);
249
+ }
245
250
  throw new Error("`bunja.use` can only be used with Bunja or Scope.");
246
251
  }),
247
252
  will: ((dep, scopeValuePairs) => {
248
253
  if (!(dep instanceof Bunja || isBunjaRef(dep))) throw new Error("`bunja.will` can only be used with Bunja.");
249
254
  const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
250
- currentBunja.addOptionalBunjaRef(toBunjaGraphRef(bunjaRef));
255
+ const graphRef = toBunjaGraphRef(bunjaRef);
256
+ currentBunja.addOptionalBunjaRef(graphRef);
251
257
  return () => {
252
258
  if (frameStack[frameStack.length - 1] !== frame) throw new Error("A thunk returned by `bunja.will` can only be called inside the same bunja init function.");
253
- return this.#useBunjaDependencyInFrame(frame, bunjaRef, "optional");
259
+ return this.#useBunjaDependencyInFrame(frame, bunjaRef);
254
260
  };
255
261
  }),
256
262
  effect: ((callback) => {
@@ -269,10 +275,8 @@ var BunjaStore = class BunjaStore {
269
275
  }
270
276
  return scopeInstance.value;
271
277
  }
272
- #useBunjaDependencyInFrame(frame, bunjaRef, edge) {
278
+ #useBunjaDependencyInFrame(frame, bunjaRef) {
273
279
  const graphRef = toBunjaGraphRef(bunjaRef);
274
- if (edge === "optional" || graphRef.scopeValuePairs.length > 0) frame.currentBunja.addOptionalBunjaRef(graphRef);
275
- else if (edge === "required") frame.currentBunja.addRequiredBunjaRef(graphRef);
276
280
  const resolved = this.#resolveBunjaRef(graphRef, frame.readScope, frame.inProgressBunjas, bunjaRef.seed);
277
281
  frame.activeDependencyIds.add(resolved.instance.id);
278
282
  frame.activeDependencyRecipes.push({
@@ -330,8 +334,9 @@ var BunjaStore = class BunjaStore {
330
334
  return readScope(dep);
331
335
  }
332
336
  if (dep instanceof Bunja || isBunjaRef(dep)) {
333
- const bunjaRef = normalizeBunjaRuntimeRef(dep, scopeValuePairs);
334
- return this.#prebakeBunjaDependencyInFrame(frame, toBunjaGraphRef(bunjaRef), "required");
337
+ const bunjaRef = toBunjaGraphRef(normalizeBunjaRuntimeRef(dep, scopeValuePairs));
338
+ currentBunja.addRequiredBunjaRef(bunjaRef);
339
+ return this.#prebakeBunjaRef(bunjaRef, readScope, prebakeContext);
335
340
  }
336
341
  throw new Error("`bunja.use` can only be used with Bunja or Scope.");
337
342
  }),
@@ -349,11 +354,6 @@ var BunjaStore = class BunjaStore {
349
354
  };
350
355
  return frame;
351
356
  }
352
- #prebakeBunjaDependencyInFrame(frame, bunjaRef, edge) {
353
- if (edge === "optional" || bunjaRef.scopeValuePairs.length > 0) frame.currentBunja.addOptionalBunjaRef(bunjaRef);
354
- else if (edge === "required") frame.currentBunja.addRequiredBunjaRef(bunjaRef);
355
- return this.#prebakeBunjaRef(bunjaRef, frame.readScope, frame.prebakeContext);
356
- }
357
357
  #resolveScopeInstanceMap(bunja$1, readScope) {
358
358
  const scopeInstanceMap = /* @__PURE__ */ new Map();
359
359
  this.#ensureRequiredScopeInstances(bunja$1, scopeInstanceMap, readScope);
@@ -484,7 +484,10 @@ var Bunja = class Bunja {
484
484
  const requiredBunjas = this.requiredBunjas;
485
485
  const expandedRequiredBunjas = toposortRequiredBunjas(requiredBunjas);
486
486
  const requiredScopeSet = /* @__PURE__ */ new Set();
487
- for (const bunja$1 of expandedRequiredBunjas) for (const scope of bunja$1.requiredScopes) requiredScopeSet.add(scope);
487
+ for (const ref of requiredBunjaRefs) {
488
+ const boundScopes = getBoundScopeSet(ref.scopeValuePairs);
489
+ for (const scope of ref.bunja.requiredScopes) if (!boundScopes.has(scope)) requiredScopeSet.add(scope);
490
+ }
488
491
  for (const scope of scopes) requiredScopeSet.add(scope);
489
492
  this.#phase = {
490
493
  baked: true,
package/dist/bunja.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_bunja = require('./bunja-BJSmIdkQ.cjs');
1
+ const require_bunja = require('./bunja-C_hneAUK.cjs');
2
2
 
3
3
  exports.Bunja = require_bunja.Bunja;
4
4
  exports.BunjaStore = require_bunja.BunjaStore;
package/dist/bunja.js CHANGED
@@ -1,3 +1,3 @@
1
- import { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-CtHOS4_Q.js";
1
+ import { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-D0Qa6gsc.js";
2
2
 
3
3
  export { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
package/dist/react.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
  const require_chunk = require('./chunk-CUT6urMc.cjs');
5
- const require_bunja = require('./bunja-BJSmIdkQ.cjs');
5
+ const require_bunja = require('./bunja-C_hneAUK.cjs');
6
6
  let react = require("react");
7
7
  react = require_chunk.__toESM(react);
8
8
 
package/dist/react.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
 
4
- import { createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-CtHOS4_Q.js";
4
+ import { createBunjaStore, createReadScopeFn, createScope, delayUnmount } from "./bunja-D0Qa6gsc.js";
5
5
  import * as React from "react";
6
6
  import { createContext, createElement, useContext, useEffect, useMemo, useState } from "react";
7
7
 
package/dist/solid.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const require_bunja = require('./bunja-BJSmIdkQ.cjs');
2
+ const require_bunja = require('./bunja-C_hneAUK.cjs');
3
3
  let solid_js = require("solid-js");
4
4
  solid_js = require_chunk.__toESM(solid_js);
5
5
 
package/dist/solid.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createBunjaStore, createReadScopeFn, createScope } from "./bunja-CtHOS4_Q.js";
1
+ import { createBunjaStore, createReadScopeFn, createScope } from "./bunja-D0Qa6gsc.js";
2
2
  import { createComponent, createContext, createEffect, createMemo, createRoot, getOwner, onCleanup, useContext } from "solid-js";
3
3
 
4
4
  //#region solid.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bunja",
3
3
  "type": "module",
4
- "version": "3.0.0-alpha.3",
4
+ "version": "3.0.0-alpha.4",
5
5
  "description": "State Lifetime Manager",
6
6
  "main": "dist/bunja.cjs",
7
7
  "module": "dist/bunja.js",
package/test.ts CHANGED
@@ -207,6 +207,32 @@ Deno.test({
207
207
  },
208
208
  });
209
209
 
210
+ Deno.test({
211
+ name: "root scope value pairs are included in store.get deps",
212
+ fn() {
213
+ const store = createBunjaStore();
214
+ const myScope = createScope<string>();
215
+ const myBunja = bunja(() => {
216
+ const scopeValue = bunja.use(myScope);
217
+ return { scopeValue };
218
+ });
219
+
220
+ const first = store.get(
221
+ { bunja: myBunja, with: [myScope.bind("foo")] },
222
+ readNull,
223
+ );
224
+ const second = store.get(
225
+ { bunja: myBunja, with: [myScope.bind("bar")] },
226
+ readNull,
227
+ );
228
+
229
+ assertEquals(first.value.scopeValue, "foo");
230
+ assertEquals(second.value.scopeValue, "bar");
231
+ assertEquals(first.deps, ["foo"]);
232
+ assertEquals(second.deps, ["bar"]);
233
+ },
234
+ });
235
+
210
236
  Deno.test({
211
237
  name: "bunja.use can override scope value pairs inside a bunja init",
212
238
  fn() {
@@ -272,6 +298,56 @@ Deno.test({
272
298
  },
273
299
  });
274
300
 
301
+ Deno.test({
302
+ name: "bunja.use with scope value pairs propagates unbound required scopes",
303
+ fn() {
304
+ const createGraph = () => {
305
+ const injectedScope = createScope<string>();
306
+ const outerScope = createScope<string>();
307
+ const dependencyBunja = bunja(() => {
308
+ const injected = bunja.use(injectedScope);
309
+ const outer = bunja.use(outerScope);
310
+ return { injected, outer };
311
+ });
312
+ const consumerBunja = bunja(() =>
313
+ bunja.use(dependencyBunja, [injectedScope.bind("injected")])
314
+ );
315
+ return { consumerBunja, injectedScope, outerScope };
316
+ };
317
+ const readScope = <T>() => "outer" as T;
318
+
319
+ const prebakeGraph = createGraph();
320
+ const { requiredScopes } = createBunjaStore().prebake(
321
+ prebakeGraph.consumerBunja,
322
+ readScope,
323
+ );
324
+ assertEquals(requiredScopes.length, 1);
325
+ assertEquals(requiredScopes[0] === prebakeGraph.outerScope, true);
326
+ assertEquals(
327
+ requiredScopes.some((scope) => scope === prebakeGraph.injectedScope),
328
+ false,
329
+ );
330
+
331
+ const getGraph = createGraph();
332
+ const { value, deps } = createBunjaStore().get(
333
+ getGraph.consumerBunja,
334
+ readScope,
335
+ );
336
+ const requiredScopes2 = getGraph.consumerBunja.requiredScopes;
337
+ assertEquals(value, { injected: "injected", outer: "outer" });
338
+ assertEquals(deps, ["outer"]);
339
+ assertEquals(requiredScopes2.length, 1);
340
+ assertEquals(
341
+ requiredScopes2[0] === getGraph.outerScope,
342
+ true,
343
+ );
344
+ assertEquals(
345
+ requiredScopes2.some((scope) => scope === getGraph.injectedScope),
346
+ false,
347
+ );
348
+ },
349
+ });
350
+
275
351
  Deno.test({
276
352
  name: "seed is used only when creating a bunja instance",
277
353
  fn() {
@@ -404,6 +480,29 @@ Deno.test({
404
480
  },
405
481
  });
406
482
 
483
+ Deno.test({
484
+ name: "bunja.will records optional refs once when thunk is used",
485
+ fn() {
486
+ const createConsumer = () => {
487
+ const dependencyBunja = bunja(() => "dependency");
488
+ const consumerBunja = bunja(() => {
489
+ const getDependency = bunja.will(dependencyBunja);
490
+ return getDependency();
491
+ });
492
+ return { consumerBunja };
493
+ };
494
+
495
+ const getGraph = createConsumer();
496
+ createBunjaStore().get(getGraph.consumerBunja, readNull);
497
+
498
+ const prebakeGraph = createConsumer();
499
+ createBunjaStore().prebake(prebakeGraph.consumerBunja, readNull);
500
+
501
+ assertEquals(getGraph.consumerBunja.optionalBunjaRefs.length, 1);
502
+ assertEquals(prebakeGraph.consumerBunja.optionalBunjaRefs.length, 1);
503
+ },
504
+ });
505
+
407
506
  Deno.test({
408
507
  name: "relatedBunjas includes nested bunja.will dependencies",
409
508
  fn() {