bunja 1.0.0 → 2.0.0-alpha.2

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.
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+
3
+ //#region bunja.ts
4
+ const bunja = bunjaFn;
5
+ function bunjaFn(init) {
6
+ return new Bunja(init);
7
+ }
8
+ bunjaFn.use = invalidUse;
9
+ bunjaFn.effect = invalidEffect;
10
+ function createScope(hash) {
11
+ return new Scope(hash);
12
+ }
13
+ function createBunjaStore() {
14
+ return new BunjaStore();
15
+ }
16
+ function invalidUse() {
17
+ throw new Error("`bunja.use` can only be used inside a bunja init function.");
18
+ }
19
+ function invalidEffect() {
20
+ throw new Error("`bunja.effect` can only be used inside a bunja init function.");
21
+ }
22
+ var BunjaStore = class {
23
+ #bunjas = {};
24
+ #scopes = new Map();
25
+ #bakingContext;
26
+ dispose() {
27
+ for (const instance of Object.values(this.#bunjas)) instance.dispose();
28
+ for (const instanceMap of Object.values(this.#scopes)) for (const instance of instanceMap.values()) instance.dispose();
29
+ this.#bunjas = {};
30
+ this.#scopes = new Map();
31
+ }
32
+ get(bunja$1, readScope) {
33
+ const originalUse = bunjaFn.use;
34
+ try {
35
+ const { bunjaInstance, bunjaInstanceMap, scopeInstanceMap } = bunja$1.baked ? this.#getBaked(bunja$1, readScope) : this.#getUnbaked(bunja$1, readScope);
36
+ return {
37
+ value: bunjaInstance.value,
38
+ mount: () => {
39
+ bunjaInstanceMap.forEach((instance) => instance.add());
40
+ bunjaInstance.add();
41
+ scopeInstanceMap.forEach((instance) => instance.add());
42
+ const unmount = () => {
43
+ setTimeout(() => {
44
+ bunjaInstanceMap.forEach((instance) => instance.sub());
45
+ bunjaInstance.sub();
46
+ scopeInstanceMap.forEach((instance) => instance.sub());
47
+ });
48
+ };
49
+ return unmount;
50
+ },
51
+ deps: Array.from(scopeInstanceMap.values()).map(({ value }) => value)
52
+ };
53
+ } finally {
54
+ bunjaFn.use = originalUse;
55
+ }
56
+ }
57
+ #getBaked(bunja$1, readScope) {
58
+ const scopeInstanceMap = new Map(bunja$1.relatedScopes.map((scope) => [scope, this.#getScopeInstance(scope, readScope(scope))]));
59
+ const bunjaInstanceMap = new Map(bunja$1.relatedBunjas.map((relatedBunja) => [relatedBunja, this.#getBunjaInstance(relatedBunja, scopeInstanceMap)]));
60
+ bunjaFn.use = (dep) => {
61
+ if (dep instanceof Bunja) return bunjaInstanceMap.get(dep).value;
62
+ if (dep instanceof Scope) return scopeInstanceMap.get(dep).value;
63
+ throw new Error("`bunja.use` can only be used with Bunja or Scope.");
64
+ };
65
+ const bunjaInstance = this.#getBunjaInstance(bunja$1, scopeInstanceMap);
66
+ return {
67
+ bunjaInstance,
68
+ bunjaInstanceMap,
69
+ scopeInstanceMap
70
+ };
71
+ }
72
+ #getUnbaked(bunja$1, readScope) {
73
+ const bunjaInstanceMap = new Map();
74
+ const scopeInstanceMap = new Map();
75
+ function getUse(map, addDep, getInstance) {
76
+ return (dep) => {
77
+ const d = dep;
78
+ addDep(d);
79
+ if (map.has(d)) return map.get(d).value;
80
+ const instance = getInstance(d);
81
+ map.set(d, instance);
82
+ return instance.value;
83
+ };
84
+ }
85
+ const useScope = getUse(scopeInstanceMap, (dep) => this.#bakingContext.currentBunja.addScope(dep), (dep) => this.#getScopeInstance(dep, readScope(dep)));
86
+ const useBunja = getUse(bunjaInstanceMap, (dep) => this.#bakingContext.currentBunja.addParent(dep), (dep) => {
87
+ if (dep.baked) for (const scope of dep.relatedScopes) useScope(scope);
88
+ return this.#getBunjaInstance(dep, scopeInstanceMap);
89
+ });
90
+ bunjaFn.use = (dep) => {
91
+ if (dep instanceof Bunja) return useBunja(dep);
92
+ if (dep instanceof Scope) return useScope(dep);
93
+ throw new Error("`bunja.use` can only be used with Bunja or Scope.");
94
+ };
95
+ try {
96
+ this.#bakingContext = { currentBunja: bunja$1 };
97
+ const bunjaInstance = this.#getBunjaInstance(bunja$1, scopeInstanceMap);
98
+ return {
99
+ bunjaInstance,
100
+ bunjaInstanceMap,
101
+ scopeInstanceMap
102
+ };
103
+ } finally {
104
+ this.#bakingContext = undefined;
105
+ }
106
+ }
107
+ #getBunjaInstance(bunja$1, scopeInstanceMap) {
108
+ const originalEffect = bunjaFn.effect;
109
+ const prevBunja = this.#bakingContext?.currentBunja;
110
+ try {
111
+ const effects = [];
112
+ bunjaFn.effect = (callback) => {
113
+ effects.push(callback);
114
+ };
115
+ if (this.#bakingContext) this.#bakingContext.currentBunja = bunja$1;
116
+ if (bunja$1.baked) {
117
+ const id = bunja$1.calcInstanceId(scopeInstanceMap);
118
+ if (id in this.#bunjas) return this.#bunjas[id];
119
+ const bunjaInstanceValue = bunja$1.init();
120
+ return this.#createBunjaInstance(id, bunjaInstanceValue, effects);
121
+ } else {
122
+ const bunjaInstanceValue = bunja$1.init();
123
+ bunja$1.bake();
124
+ const id = bunja$1.calcInstanceId(scopeInstanceMap);
125
+ return this.#createBunjaInstance(id, bunjaInstanceValue, effects);
126
+ }
127
+ } finally {
128
+ bunjaFn.effect = originalEffect;
129
+ if (this.#bakingContext) this.#bakingContext.currentBunja = prevBunja;
130
+ }
131
+ }
132
+ #getScopeInstance(scope, value) {
133
+ const key = scope.hash(value);
134
+ const instanceMap = this.#scopes.get(scope) ?? this.#scopes.set(scope, new Map()).get(scope);
135
+ return instanceMap.get(key) ?? instanceMap.set(key, new ScopeInstance(value, () => instanceMap.delete(key))).get(key);
136
+ }
137
+ #createBunjaInstance(id, value, effects) {
138
+ const effect = () => {
139
+ const cleanups = effects.map((effect$1) => effect$1()).filter(Boolean);
140
+ return () => cleanups.forEach((cleanup) => cleanup());
141
+ };
142
+ const dispose = () => delete this.#bunjas[id];
143
+ const bunjaInstance = new BunjaInstance(id, value, effect, dispose);
144
+ this.#bunjas[id] = bunjaInstance;
145
+ return bunjaInstance;
146
+ }
147
+ };
148
+ var Bunja = class Bunja {
149
+ static counter = 0;
150
+ id = String(Bunja.counter++);
151
+ debugLabel = "";
152
+ #phase = {
153
+ baked: false,
154
+ parents: new Set(),
155
+ scopes: new Set()
156
+ };
157
+ constructor(init) {
158
+ this.init = init;
159
+ }
160
+ get baked() {
161
+ return this.#phase.baked;
162
+ }
163
+ get parents() {
164
+ if (this.#phase.baked) return this.#phase.parents;
165
+ return Array.from(this.#phase.parents);
166
+ }
167
+ get relatedBunjas() {
168
+ if (!this.#phase.baked) throw new Error("Bunja is not baked yet.");
169
+ return this.#phase.relatedBunjas;
170
+ }
171
+ get relatedScopes() {
172
+ if (!this.#phase.baked) throw new Error("Bunja is not baked yet.");
173
+ return this.#phase.relatedScopes;
174
+ }
175
+ addParent(bunja$1) {
176
+ if (this.#phase.baked) return;
177
+ this.#phase.parents.add(bunja$1);
178
+ }
179
+ addScope(scope) {
180
+ if (this.#phase.baked) return;
181
+ this.#phase.scopes.add(scope);
182
+ }
183
+ bake() {
184
+ if (this.#phase.baked) throw new Error("Bunja is already baked.");
185
+ const scopes = this.#phase.scopes;
186
+ const parents = this.parents;
187
+ const relatedBunjas = toposort(parents);
188
+ const relatedScopes = Array.from(new Set([...relatedBunjas.flatMap((bunja$1) => bunja$1.relatedScopes), ...scopes]));
189
+ this.#phase = {
190
+ baked: true,
191
+ parents,
192
+ relatedBunjas,
193
+ relatedScopes
194
+ };
195
+ }
196
+ calcInstanceId(scopeInstanceMap) {
197
+ const scopeInstanceIds = this.relatedScopes.map((scope) => scopeInstanceMap.get(scope).id);
198
+ return `${this.id}:${scopeInstanceIds.join(",")}`;
199
+ }
200
+ toString() {
201
+ const { id, debugLabel } = this;
202
+ return `[Bunja:${id}${debugLabel && ` - ${debugLabel}`}]`;
203
+ }
204
+ };
205
+ var Scope = class Scope {
206
+ static counter = 0;
207
+ id = String(Scope.counter++);
208
+ debugLabel = "";
209
+ constructor(hash = Scope.identity) {
210
+ this.hash = hash;
211
+ }
212
+ static identity(x) {
213
+ return x;
214
+ }
215
+ toString() {
216
+ const { id, debugLabel } = this;
217
+ return `[Scope:${id}${debugLabel && ` - ${debugLabel}`}]`;
218
+ }
219
+ };
220
+ const noop = () => {};
221
+ var RefCounter = class {
222
+ #count = 0;
223
+ add() {
224
+ ++this.#count;
225
+ }
226
+ sub() {
227
+ --this.#count;
228
+ if (this.#count < 1) {
229
+ this.dispose();
230
+ this.dispose = noop;
231
+ }
232
+ }
233
+ };
234
+ var BunjaInstance = class extends RefCounter {
235
+ #cleanup;
236
+ constructor(id, value, effect, _dispose) {
237
+ super();
238
+ this.id = id;
239
+ this.value = value;
240
+ this.effect = effect;
241
+ this._dispose = _dispose;
242
+ }
243
+ dispose() {
244
+ this.#cleanup?.();
245
+ this._dispose();
246
+ }
247
+ add() {
248
+ this.#cleanup ??= this.effect() ?? noop;
249
+ super.add();
250
+ }
251
+ };
252
+ var ScopeInstance = class ScopeInstance extends RefCounter {
253
+ static counter = 0;
254
+ id = String(ScopeInstance.counter++);
255
+ constructor(value, dispose) {
256
+ super();
257
+ this.value = value;
258
+ this.dispose = dispose;
259
+ }
260
+ };
261
+ function toposort(nodes) {
262
+ const visited = new Set();
263
+ const result = [];
264
+ function visit(current) {
265
+ if (visited.has(current)) return;
266
+ visited.add(current);
267
+ for (const parent of current.parents) visit(parent);
268
+ result.push(current);
269
+ }
270
+ for (const node of nodes) visit(node);
271
+ return result;
272
+ }
273
+
274
+ //#endregion
275
+ Object.defineProperty(exports, 'Bunja', {
276
+ enumerable: true,
277
+ get: function () {
278
+ return Bunja;
279
+ }
280
+ });Object.defineProperty(exports, 'BunjaStore', {
281
+ enumerable: true,
282
+ get: function () {
283
+ return BunjaStore;
284
+ }
285
+ });Object.defineProperty(exports, 'Scope', {
286
+ enumerable: true,
287
+ get: function () {
288
+ return Scope;
289
+ }
290
+ });Object.defineProperty(exports, 'bunja', {
291
+ enumerable: true,
292
+ get: function () {
293
+ return bunja;
294
+ }
295
+ });Object.defineProperty(exports, 'createBunjaStore', {
296
+ enumerable: true,
297
+ get: function () {
298
+ return createBunjaStore;
299
+ }
300
+ });Object.defineProperty(exports, 'createScope', {
301
+ enumerable: true,
302
+ get: function () {
303
+ return createScope;
304
+ }
305
+ });
@@ -0,0 +1,274 @@
1
+
2
+ //#region bunja.ts
3
+ const bunja = bunjaFn;
4
+ function bunjaFn(init) {
5
+ return new Bunja(init);
6
+ }
7
+ bunjaFn.use = invalidUse;
8
+ bunjaFn.effect = invalidEffect;
9
+ function createScope(hash) {
10
+ return new Scope(hash);
11
+ }
12
+ function createBunjaStore() {
13
+ return new BunjaStore();
14
+ }
15
+ function invalidUse() {
16
+ throw new Error("`bunja.use` can only be used inside a bunja init function.");
17
+ }
18
+ function invalidEffect() {
19
+ throw new Error("`bunja.effect` can only be used inside a bunja init function.");
20
+ }
21
+ var BunjaStore = class {
22
+ #bunjas = {};
23
+ #scopes = new Map();
24
+ #bakingContext;
25
+ dispose() {
26
+ for (const instance of Object.values(this.#bunjas)) instance.dispose();
27
+ for (const instanceMap of Object.values(this.#scopes)) for (const instance of instanceMap.values()) instance.dispose();
28
+ this.#bunjas = {};
29
+ this.#scopes = new Map();
30
+ }
31
+ get(bunja$1, readScope) {
32
+ const originalUse = bunjaFn.use;
33
+ try {
34
+ const { bunjaInstance, bunjaInstanceMap, scopeInstanceMap } = bunja$1.baked ? this.#getBaked(bunja$1, readScope) : this.#getUnbaked(bunja$1, readScope);
35
+ return {
36
+ value: bunjaInstance.value,
37
+ mount: () => {
38
+ bunjaInstanceMap.forEach((instance) => instance.add());
39
+ bunjaInstance.add();
40
+ scopeInstanceMap.forEach((instance) => instance.add());
41
+ const unmount = () => {
42
+ setTimeout(() => {
43
+ bunjaInstanceMap.forEach((instance) => instance.sub());
44
+ bunjaInstance.sub();
45
+ scopeInstanceMap.forEach((instance) => instance.sub());
46
+ });
47
+ };
48
+ return unmount;
49
+ },
50
+ deps: Array.from(scopeInstanceMap.values()).map(({ value }) => value)
51
+ };
52
+ } finally {
53
+ bunjaFn.use = originalUse;
54
+ }
55
+ }
56
+ #getBaked(bunja$1, readScope) {
57
+ const scopeInstanceMap = new Map(bunja$1.relatedScopes.map((scope) => [scope, this.#getScopeInstance(scope, readScope(scope))]));
58
+ const bunjaInstanceMap = new Map(bunja$1.relatedBunjas.map((relatedBunja) => [relatedBunja, this.#getBunjaInstance(relatedBunja, scopeInstanceMap)]));
59
+ bunjaFn.use = (dep) => {
60
+ if (dep instanceof Bunja) return bunjaInstanceMap.get(dep).value;
61
+ if (dep instanceof Scope) return scopeInstanceMap.get(dep).value;
62
+ throw new Error("`bunja.use` can only be used with Bunja or Scope.");
63
+ };
64
+ const bunjaInstance = this.#getBunjaInstance(bunja$1, scopeInstanceMap);
65
+ return {
66
+ bunjaInstance,
67
+ bunjaInstanceMap,
68
+ scopeInstanceMap
69
+ };
70
+ }
71
+ #getUnbaked(bunja$1, readScope) {
72
+ const bunjaInstanceMap = new Map();
73
+ const scopeInstanceMap = new Map();
74
+ function getUse(map, addDep, getInstance) {
75
+ return (dep) => {
76
+ const d = dep;
77
+ addDep(d);
78
+ if (map.has(d)) return map.get(d).value;
79
+ const instance = getInstance(d);
80
+ map.set(d, instance);
81
+ return instance.value;
82
+ };
83
+ }
84
+ const useScope = getUse(scopeInstanceMap, (dep) => this.#bakingContext.currentBunja.addScope(dep), (dep) => this.#getScopeInstance(dep, readScope(dep)));
85
+ const useBunja = getUse(bunjaInstanceMap, (dep) => this.#bakingContext.currentBunja.addParent(dep), (dep) => {
86
+ if (dep.baked) for (const scope of dep.relatedScopes) useScope(scope);
87
+ return this.#getBunjaInstance(dep, scopeInstanceMap);
88
+ });
89
+ bunjaFn.use = (dep) => {
90
+ if (dep instanceof Bunja) return useBunja(dep);
91
+ if (dep instanceof Scope) return useScope(dep);
92
+ throw new Error("`bunja.use` can only be used with Bunja or Scope.");
93
+ };
94
+ try {
95
+ this.#bakingContext = { currentBunja: bunja$1 };
96
+ const bunjaInstance = this.#getBunjaInstance(bunja$1, scopeInstanceMap);
97
+ return {
98
+ bunjaInstance,
99
+ bunjaInstanceMap,
100
+ scopeInstanceMap
101
+ };
102
+ } finally {
103
+ this.#bakingContext = undefined;
104
+ }
105
+ }
106
+ #getBunjaInstance(bunja$1, scopeInstanceMap) {
107
+ const originalEffect = bunjaFn.effect;
108
+ const prevBunja = this.#bakingContext?.currentBunja;
109
+ try {
110
+ const effects = [];
111
+ bunjaFn.effect = (callback) => {
112
+ effects.push(callback);
113
+ };
114
+ if (this.#bakingContext) this.#bakingContext.currentBunja = bunja$1;
115
+ if (bunja$1.baked) {
116
+ const id = bunja$1.calcInstanceId(scopeInstanceMap);
117
+ if (id in this.#bunjas) return this.#bunjas[id];
118
+ const bunjaInstanceValue = bunja$1.init();
119
+ return this.#createBunjaInstance(id, bunjaInstanceValue, effects);
120
+ } else {
121
+ const bunjaInstanceValue = bunja$1.init();
122
+ bunja$1.bake();
123
+ const id = bunja$1.calcInstanceId(scopeInstanceMap);
124
+ return this.#createBunjaInstance(id, bunjaInstanceValue, effects);
125
+ }
126
+ } finally {
127
+ bunjaFn.effect = originalEffect;
128
+ if (this.#bakingContext) this.#bakingContext.currentBunja = prevBunja;
129
+ }
130
+ }
131
+ #getScopeInstance(scope, value) {
132
+ const key = scope.hash(value);
133
+ const instanceMap = this.#scopes.get(scope) ?? this.#scopes.set(scope, new Map()).get(scope);
134
+ return instanceMap.get(key) ?? instanceMap.set(key, new ScopeInstance(value, () => instanceMap.delete(key))).get(key);
135
+ }
136
+ #createBunjaInstance(id, value, effects) {
137
+ const effect = () => {
138
+ const cleanups = effects.map((effect$1) => effect$1()).filter(Boolean);
139
+ return () => cleanups.forEach((cleanup) => cleanup());
140
+ };
141
+ const dispose = () => delete this.#bunjas[id];
142
+ const bunjaInstance = new BunjaInstance(id, value, effect, dispose);
143
+ this.#bunjas[id] = bunjaInstance;
144
+ return bunjaInstance;
145
+ }
146
+ };
147
+ var Bunja = class Bunja {
148
+ static counter = 0;
149
+ id = String(Bunja.counter++);
150
+ debugLabel = "";
151
+ #phase = {
152
+ baked: false,
153
+ parents: new Set(),
154
+ scopes: new Set()
155
+ };
156
+ constructor(init) {
157
+ this.init = init;
158
+ }
159
+ get baked() {
160
+ return this.#phase.baked;
161
+ }
162
+ get parents() {
163
+ if (this.#phase.baked) return this.#phase.parents;
164
+ return Array.from(this.#phase.parents);
165
+ }
166
+ get relatedBunjas() {
167
+ if (!this.#phase.baked) throw new Error("Bunja is not baked yet.");
168
+ return this.#phase.relatedBunjas;
169
+ }
170
+ get relatedScopes() {
171
+ if (!this.#phase.baked) throw new Error("Bunja is not baked yet.");
172
+ return this.#phase.relatedScopes;
173
+ }
174
+ addParent(bunja$1) {
175
+ if (this.#phase.baked) return;
176
+ this.#phase.parents.add(bunja$1);
177
+ }
178
+ addScope(scope) {
179
+ if (this.#phase.baked) return;
180
+ this.#phase.scopes.add(scope);
181
+ }
182
+ bake() {
183
+ if (this.#phase.baked) throw new Error("Bunja is already baked.");
184
+ const scopes = this.#phase.scopes;
185
+ const parents = this.parents;
186
+ const relatedBunjas = toposort(parents);
187
+ const relatedScopes = Array.from(new Set([...relatedBunjas.flatMap((bunja$1) => bunja$1.relatedScopes), ...scopes]));
188
+ this.#phase = {
189
+ baked: true,
190
+ parents,
191
+ relatedBunjas,
192
+ relatedScopes
193
+ };
194
+ }
195
+ calcInstanceId(scopeInstanceMap) {
196
+ const scopeInstanceIds = this.relatedScopes.map((scope) => scopeInstanceMap.get(scope).id);
197
+ return `${this.id}:${scopeInstanceIds.join(",")}`;
198
+ }
199
+ toString() {
200
+ const { id, debugLabel } = this;
201
+ return `[Bunja:${id}${debugLabel && ` - ${debugLabel}`}]`;
202
+ }
203
+ };
204
+ var Scope = class Scope {
205
+ static counter = 0;
206
+ id = String(Scope.counter++);
207
+ debugLabel = "";
208
+ constructor(hash = Scope.identity) {
209
+ this.hash = hash;
210
+ }
211
+ static identity(x) {
212
+ return x;
213
+ }
214
+ toString() {
215
+ const { id, debugLabel } = this;
216
+ return `[Scope:${id}${debugLabel && ` - ${debugLabel}`}]`;
217
+ }
218
+ };
219
+ const noop = () => {};
220
+ var RefCounter = class {
221
+ #count = 0;
222
+ add() {
223
+ ++this.#count;
224
+ }
225
+ sub() {
226
+ --this.#count;
227
+ if (this.#count < 1) {
228
+ this.dispose();
229
+ this.dispose = noop;
230
+ }
231
+ }
232
+ };
233
+ var BunjaInstance = class extends RefCounter {
234
+ #cleanup;
235
+ constructor(id, value, effect, _dispose) {
236
+ super();
237
+ this.id = id;
238
+ this.value = value;
239
+ this.effect = effect;
240
+ this._dispose = _dispose;
241
+ }
242
+ dispose() {
243
+ this.#cleanup?.();
244
+ this._dispose();
245
+ }
246
+ add() {
247
+ this.#cleanup ??= this.effect() ?? noop;
248
+ super.add();
249
+ }
250
+ };
251
+ var ScopeInstance = class ScopeInstance extends RefCounter {
252
+ static counter = 0;
253
+ id = String(ScopeInstance.counter++);
254
+ constructor(value, dispose) {
255
+ super();
256
+ this.value = value;
257
+ this.dispose = dispose;
258
+ }
259
+ };
260
+ function toposort(nodes) {
261
+ const visited = new Set();
262
+ const result = [];
263
+ function visit(current) {
264
+ if (visited.has(current)) return;
265
+ visited.add(current);
266
+ for (const parent of current.parents) visit(parent);
267
+ result.push(current);
268
+ }
269
+ for (const node of nodes) visit(node);
270
+ return result;
271
+ }
272
+
273
+ //#endregion
274
+ export { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createScope };
package/dist/bunja.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const require_bunja = require('./bunja-Q0ZusYIM.cjs');
2
+ const require_bunja = require('./bunja-bUA1rGXy.cjs');
3
3
 
4
4
  exports.Bunja = require_bunja.Bunja
5
5
  exports.BunjaStore = require_bunja.BunjaStore
package/dist/bunja.d.cts CHANGED
@@ -1,55 +1,64 @@
1
+ export interface BunjaFn {
2
+ <T>(init: () => T): Bunja<T>;
3
+ use: BunjaUseFn;
4
+ effect: BunjaEffectFn;
5
+ }
6
+ export declare const bunja: BunjaFn;
7
+ export type BunjaUseFn = <T>(dep: Dep<T>) => T;
8
+ export type BunjaEffectFn = (callback: BunjaEffectCallback) => void;
9
+ export type BunjaEffectCallback = () => (() => void) | void;
10
+ export declare function createScope<T>(hash?: HashFn<T>): Scope<T>;
11
+ export declare function createBunjaStore(): BunjaStore;
1
12
  export type Dep<T> = Bunja<T> | Scope<T>;
2
- declare const bunjaEffectSymbol: unique symbol;
3
- type BunjaEffectSymbol = typeof bunjaEffectSymbol;
13
+ export declare class BunjaStore {
14
+ #private;
15
+ dispose(): void;
16
+ get<T>(bunja: Bunja<T>, readScope: ReadScope): BunjaStoreGetResult<T>;
17
+ }
18
+ export type ReadScope = <T>(scope: Scope<T>) => T;
19
+ export interface BunjaStoreGetResult<T> {
20
+ value: T;
21
+ mount: () => () => void;
22
+ deps: unknown[];
23
+ }
4
24
  export declare class Bunja<T> {
5
- deps: Dep<any>[];
6
- parents: Bunja<any>[];
7
- relatedBunjas: Bunja<any>[];
8
- relatedScopes: Scope<any>[];
9
- init: (...args: any[]) => T & BunjaValue;
10
- static readonly bunjas: Bunja<any>[];
11
- readonly id: number;
25
+ #private;
26
+ init: () => T;
27
+ private static counter;
28
+ readonly id: string;
12
29
  debugLabel: string;
13
- constructor(deps: Dep<any>[], // one depth dependencies
14
- parents: Bunja<any>[], // one depth parents
15
- relatedBunjas: Bunja<any>[], // toposorted parents without self
16
- relatedScopes: Scope<any>[], // deduped
17
- init: (...args: any[]) => T & BunjaValue);
18
- static readonly effect: BunjaEffectSymbol;
30
+ constructor(init: () => T);
31
+ get baked(): boolean;
32
+ get parents(): Bunja<unknown>[];
33
+ get relatedBunjas(): Bunja<unknown>[];
34
+ get relatedScopes(): Scope<unknown>[];
35
+ addParent(bunja: Bunja<unknown>): void;
36
+ addScope(scope: Scope<unknown>): void;
37
+ bake(): void;
38
+ calcInstanceId(scopeInstanceMap: Map<Scope<unknown>, ScopeInstance>): string;
19
39
  toString(): string;
20
40
  }
21
- export type HashFn<T = any, U = any> = (value: T) => U;
22
41
  export declare class Scope<T> {
23
- readonly hash: HashFn;
24
- static readonly scopes: Scope<any>[];
25
- readonly id: number;
42
+ readonly hash: HashFn<T>;
43
+ private static counter;
44
+ readonly id: string;
26
45
  debugLabel: string;
27
- constructor(hash?: HashFn);
46
+ constructor(hash?: HashFn<T>);
47
+ private static identity;
28
48
  toString(): string;
29
49
  }
30
- export type ReadScope = <T>(scope: Scope<T>) => T;
31
- export declare class BunjaStore {
50
+ export type HashFn<T> = (value: T) => unknown;
51
+ declare abstract class RefCounter {
32
52
  #private;
33
- get<T>(bunja: Bunja<T>, readScope: ReadScope): {
34
- value: T;
35
- mount: () => () => void;
36
- deps: any[];
37
- };
53
+ abstract dispose(): void;
54
+ add(): void;
55
+ sub(): void;
38
56
  }
39
- export declare const createBunjaStore: () => BunjaStore;
40
- export type BunjaEffectFn = () => () => void;
41
- export interface BunjaValue {
42
- [Bunja.effect]?: BunjaEffectFn;
57
+ declare class ScopeInstance extends RefCounter {
58
+ readonly value: unknown;
59
+ readonly dispose: () => void;
60
+ private static counter;
61
+ readonly id: string;
62
+ constructor(value: unknown, dispose: () => void);
43
63
  }
44
- export declare const bunja: {
45
- <T>(deps: [], init: () => T & BunjaValue): Bunja<T>;
46
- <T, U>(deps: [Dep<U>], init: (u: U) => T & BunjaValue): Bunja<T>;
47
- <T, U, V>(deps: [Dep<U>, Dep<V>], init: (u: U, v: V) => T & BunjaValue): Bunja<T>;
48
- <T, U, V, W>(deps: [Dep<U>, Dep<V>, Dep<W>], init: (u: U, v: V, w: W) => T & BunjaValue): Bunja<T>;
49
- <T, U, V, W, X>(deps: [Dep<U>, Dep<V>, Dep<W>, Dep<X>], init: (u: U, v: V, w: W, x: X) => T & BunjaValue): Bunja<T>;
50
- <T, U, V, W, X, Y>(deps: [Dep<U>, Dep<V>, Dep<W>, Dep<X>, Dep<Y>], init: (u: U, v: V, w: W, x: X, y: Y) => T & BunjaValue): Bunja<T>;
51
- <T, U, V, W, X, Y, Z>(deps: [Dep<U>, Dep<V>, Dep<W>, Dep<X>, Dep<Y>, Dep<Z>], init: (u: U, v: V, w: W, x: X, y: Y, z: Z) => T & BunjaValue): Bunja<T>;
52
- readonly effect: BunjaEffectSymbol;
53
- };
54
- export declare function createScope<T>(hash?: HashFn): Scope<T>;
55
64
  export {};