bunja 2.1.0 → 3.0.0-alpha.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/README.md +135 -4
- package/bunja.ts +847 -222
- package/deno.json +1 -1
- package/dist/bunja-BJSmIdkQ.cjs +682 -0
- package/dist/{bunja-BKpQTG04.d.cts → bunja-BxbzuHdH.d.cts} +73 -19
- package/dist/bunja-CtHOS4_Q.js +634 -0
- package/dist/{bunja-B_HNgDan.d.ts → bunja-DEFeIlpt.d.ts} +73 -19
- package/dist/bunja.cjs +1 -1
- package/dist/bunja.d.cts +2 -2
- package/dist/bunja.d.ts +2 -2
- package/dist/bunja.js +1 -1
- package/dist/react.cjs +16 -4
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/react.js +17 -4
- package/dist/solid.cjs +1 -1
- package/dist/solid.d.cts +2 -2
- package/dist/solid.d.ts +2 -2
- package/dist/solid.js +1 -1
- package/package.json +2 -2
- package/react.ts +34 -8
- package/solid.ts +4 -3
- package/test.ts +434 -4
- package/dist/bunja-BOUkMIz6.js +0 -396
- package/dist/bunja-DFFVW7Gi.cjs +0 -444
package/dist/bunja-BOUkMIz6.js
DELETED
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
//#region bunja.ts
|
|
2
|
-
const __DEV__ = process.env.NODE_ENV !== "production";
|
|
3
|
-
const bunja = bunjaFn;
|
|
4
|
-
function bunjaFn(init) {
|
|
5
|
-
return new Bunja(init);
|
|
6
|
-
}
|
|
7
|
-
bunjaFn.use = invalidUse;
|
|
8
|
-
bunjaFn.fork = invalidFork;
|
|
9
|
-
bunjaFn.effect = invalidEffect;
|
|
10
|
-
function createScope(hash) {
|
|
11
|
-
return new Scope(hash);
|
|
12
|
-
}
|
|
13
|
-
function createBunjaStore(config) {
|
|
14
|
-
const { wrapInstance = defaultWrapInstanceFn } = config ?? {};
|
|
15
|
-
const store = new BunjaStore();
|
|
16
|
-
store.wrapInstance = wrapInstance;
|
|
17
|
-
return store;
|
|
18
|
-
}
|
|
19
|
-
function invalidUse() {
|
|
20
|
-
throw new Error("`bunja.use` can only be used inside a bunja init function.");
|
|
21
|
-
}
|
|
22
|
-
function invalidFork() {
|
|
23
|
-
throw new Error("`bunja.fork` can only be used inside a bunja init function.");
|
|
24
|
-
}
|
|
25
|
-
function invalidEffect() {
|
|
26
|
-
throw new Error("`bunja.effect` can only be used inside a bunja init function.");
|
|
27
|
-
}
|
|
28
|
-
const defaultWrapInstanceFn = (fn) => fn(noop);
|
|
29
|
-
var BunjaStore = class BunjaStore {
|
|
30
|
-
static counter = 0;
|
|
31
|
-
id = String(BunjaStore.counter++);
|
|
32
|
-
#bunjas = {};
|
|
33
|
-
#scopes = /* @__PURE__ */ new Map();
|
|
34
|
-
#bakingContext;
|
|
35
|
-
wrapInstance = defaultWrapInstanceFn;
|
|
36
|
-
constructor() {
|
|
37
|
-
if (__DEV__) {
|
|
38
|
-
devtoolsGlobalHook.stores[this.id] = this;
|
|
39
|
-
devtoolsGlobalHook.emit("storeCreated", { storeId: this.id });
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
get _internalState() {
|
|
43
|
-
if (__DEV__) return {
|
|
44
|
-
bunjas: this.#bunjas,
|
|
45
|
-
scopes: this.#scopes,
|
|
46
|
-
get instantiating() {
|
|
47
|
-
return bunja.use != invalidUse;
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
dispose() {
|
|
52
|
-
for (const instance of Object.values(this.#bunjas)) instance.dispose();
|
|
53
|
-
for (const instanceMap of Object.values(this.#scopes)) for (const instance of instanceMap.values()) instance.dispose();
|
|
54
|
-
this.#bunjas = {};
|
|
55
|
-
this.#scopes = /* @__PURE__ */ new Map();
|
|
56
|
-
if (__DEV__) {
|
|
57
|
-
devtoolsGlobalHook.emit("storeDisposed", { storeId: this.id });
|
|
58
|
-
delete devtoolsGlobalHook.stores[this.id];
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
get(bunja$1, readScope) {
|
|
62
|
-
const originalUse = bunjaFn.use;
|
|
63
|
-
try {
|
|
64
|
-
const { bunjaInstance, bunjaInstanceMap, scopeInstanceMap } = bunja$1.baked ? this.#getBaked(bunja$1, readScope) : this.#getUnbaked(bunja$1, readScope);
|
|
65
|
-
const result = {
|
|
66
|
-
value: bunjaInstance.value,
|
|
67
|
-
mount: () => {
|
|
68
|
-
bunjaInstanceMap.forEach((instance) => instance.add());
|
|
69
|
-
bunjaInstance.add();
|
|
70
|
-
scopeInstanceMap.forEach((instance) => instance.add());
|
|
71
|
-
const unmount = () => {
|
|
72
|
-
bunjaInstanceMap.forEach((instance) => instance.sub());
|
|
73
|
-
bunjaInstance.sub();
|
|
74
|
-
scopeInstanceMap.forEach((instance) => instance.sub());
|
|
75
|
-
};
|
|
76
|
-
return unmount;
|
|
77
|
-
},
|
|
78
|
-
deps: Array.from(scopeInstanceMap.values()).map(({ value }) => value)
|
|
79
|
-
};
|
|
80
|
-
if (__DEV__) {
|
|
81
|
-
result.bunjaInstance = bunjaInstance;
|
|
82
|
-
devtoolsGlobalHook.emit("getCalled", {
|
|
83
|
-
storeId: this.id,
|
|
84
|
-
bunjaInstanceId: bunjaInstance.id
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
return result;
|
|
88
|
-
} finally {
|
|
89
|
-
bunjaFn.use = originalUse;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
#getBaked(bunja$1, readScope) {
|
|
93
|
-
const scopeInstanceMap = new Map(bunja$1.relatedScopes.map((scope) => [scope, this.#getScopeInstance(scope, readScope(scope))]));
|
|
94
|
-
const bunjaInstanceMap = /* @__PURE__ */ new Map();
|
|
95
|
-
bunjaFn.use = (dep) => {
|
|
96
|
-
if (dep instanceof Bunja) return bunjaInstanceMap.get(dep).value;
|
|
97
|
-
if (dep instanceof Scope) return scopeInstanceMap.get(dep).value;
|
|
98
|
-
throw new Error("`bunja.use` can only be used with Bunja or Scope.");
|
|
99
|
-
};
|
|
100
|
-
for (const relatedBunja of bunja$1.relatedBunjas) bunjaInstanceMap.set(relatedBunja, this.#getBunjaInstance(relatedBunja, scopeInstanceMap));
|
|
101
|
-
return {
|
|
102
|
-
bunjaInstance: this.#getBunjaInstance(bunja$1, scopeInstanceMap),
|
|
103
|
-
bunjaInstanceMap,
|
|
104
|
-
scopeInstanceMap
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
#getUnbaked(bunja$1, readScope) {
|
|
108
|
-
const bunjaInstanceMap = /* @__PURE__ */ new Map();
|
|
109
|
-
const scopeInstanceMap = /* @__PURE__ */ new Map();
|
|
110
|
-
function getUse(map, addDep, getInstance) {
|
|
111
|
-
return ((dep) => {
|
|
112
|
-
const d = dep;
|
|
113
|
-
addDep(d);
|
|
114
|
-
if (map.has(d)) return map.get(d).value;
|
|
115
|
-
const instance = getInstance(d);
|
|
116
|
-
map.set(d, instance);
|
|
117
|
-
return instance.value;
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
const useScope = getUse(scopeInstanceMap, (dep) => this.#bakingContext.currentBunja.addScope(dep), (dep) => this.#getScopeInstance(dep, readScope(dep)));
|
|
121
|
-
const useBunja = getUse(bunjaInstanceMap, (dep) => this.#bakingContext.currentBunja.addParent(dep), (dep) => {
|
|
122
|
-
if (dep.baked) for (const scope of dep.relatedScopes) useScope(scope);
|
|
123
|
-
return this.#getBunjaInstance(dep, scopeInstanceMap);
|
|
124
|
-
});
|
|
125
|
-
bunjaFn.use = (dep) => {
|
|
126
|
-
if (dep instanceof Bunja) return useBunja(dep);
|
|
127
|
-
if (dep instanceof Scope) return useScope(dep);
|
|
128
|
-
throw new Error("`bunja.use` can only be used with Bunja or Scope.");
|
|
129
|
-
};
|
|
130
|
-
const originalBakingContext = this.#bakingContext;
|
|
131
|
-
try {
|
|
132
|
-
this.#bakingContext = { currentBunja: bunja$1 };
|
|
133
|
-
return {
|
|
134
|
-
bunjaInstance: this.#getBunjaInstance(bunja$1, scopeInstanceMap),
|
|
135
|
-
bunjaInstanceMap,
|
|
136
|
-
scopeInstanceMap
|
|
137
|
-
};
|
|
138
|
-
} finally {
|
|
139
|
-
this.#bakingContext = originalBakingContext;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
#getBunjaInstance(bunja$1, scopeInstanceMap) {
|
|
143
|
-
const originalEffect = bunjaFn.effect;
|
|
144
|
-
const originalFork = bunjaFn.fork;
|
|
145
|
-
const prevBunja = this.#bakingContext?.currentBunja;
|
|
146
|
-
try {
|
|
147
|
-
const effects = [];
|
|
148
|
-
bunjaFn.effect = (callback) => {
|
|
149
|
-
effects.push(callback);
|
|
150
|
-
};
|
|
151
|
-
bunjaFn.fork = (b, scopeValuePairs) => {
|
|
152
|
-
const readScope = createReadScopeFn(scopeValuePairs, bunjaFn.use);
|
|
153
|
-
const { value, mount } = this.get(b, readScope);
|
|
154
|
-
bunjaFn.effect(mount);
|
|
155
|
-
return value;
|
|
156
|
-
};
|
|
157
|
-
if (this.#bakingContext) this.#bakingContext.currentBunja = bunja$1;
|
|
158
|
-
if (bunja$1.baked) {
|
|
159
|
-
const id = bunja$1.calcInstanceId(scopeInstanceMap);
|
|
160
|
-
if (id in this.#bunjas) return this.#bunjas[id];
|
|
161
|
-
return this.wrapInstance((dispose) => {
|
|
162
|
-
const value = bunja$1.init();
|
|
163
|
-
return this.#createBunjaInstance(id, value, effects, dispose);
|
|
164
|
-
});
|
|
165
|
-
} else return this.wrapInstance((dispose) => {
|
|
166
|
-
const value = bunja$1.init();
|
|
167
|
-
bunja$1.bake();
|
|
168
|
-
const id = bunja$1.calcInstanceId(scopeInstanceMap);
|
|
169
|
-
return this.#createBunjaInstance(id, value, effects, dispose);
|
|
170
|
-
});
|
|
171
|
-
} finally {
|
|
172
|
-
bunjaFn.effect = originalEffect;
|
|
173
|
-
bunjaFn.fork = originalFork;
|
|
174
|
-
if (this.#bakingContext) this.#bakingContext.currentBunja = prevBunja;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
#getScopeInstance(scope, value) {
|
|
178
|
-
const key = scope.hash(value);
|
|
179
|
-
const instanceMap = this.#scopes.get(scope) ?? this.#scopes.set(scope, /* @__PURE__ */ new Map()).get(scope);
|
|
180
|
-
return instanceMap.get(key) ?? instanceMap.set(key, this.#createScopeInstance(scope, key, value, () => {
|
|
181
|
-
instanceMap.delete(key);
|
|
182
|
-
if (__DEV__) devtoolsGlobalHook.emit("scopeInstanceUnmounted", {
|
|
183
|
-
storeId: this.id,
|
|
184
|
-
scope,
|
|
185
|
-
key
|
|
186
|
-
});
|
|
187
|
-
})).get(key);
|
|
188
|
-
}
|
|
189
|
-
#createBunjaInstance(id, value, effects, dispose) {
|
|
190
|
-
const effect = () => {
|
|
191
|
-
const cleanups = effects.map((effect$1) => effect$1()).filter(Boolean);
|
|
192
|
-
return () => cleanups.forEach((cleanup) => cleanup());
|
|
193
|
-
};
|
|
194
|
-
const bunjaInstance = new BunjaInstance(id, value, effect, () => {
|
|
195
|
-
if (__DEV__) devtoolsGlobalHook.emit("bunjaInstanceUnmounted", {
|
|
196
|
-
storeId: this.id,
|
|
197
|
-
bunjaInstanceId: id
|
|
198
|
-
});
|
|
199
|
-
dispose();
|
|
200
|
-
delete this.#bunjas[id];
|
|
201
|
-
});
|
|
202
|
-
this.#bunjas[id] = bunjaInstance;
|
|
203
|
-
if (__DEV__) devtoolsGlobalHook.emit("bunjaInstanceMounted", {
|
|
204
|
-
storeId: this.id,
|
|
205
|
-
bunjaInstanceId: id
|
|
206
|
-
});
|
|
207
|
-
return bunjaInstance;
|
|
208
|
-
}
|
|
209
|
-
#createScopeInstance(scope, key, value, dispose) {
|
|
210
|
-
if (__DEV__) devtoolsGlobalHook.emit("scopeInstanceMounted", {
|
|
211
|
-
storeId: this.id,
|
|
212
|
-
scope,
|
|
213
|
-
key
|
|
214
|
-
});
|
|
215
|
-
return new ScopeInstance(value, dispose);
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
function createReadScopeFn(scopeValuePairs, readScope) {
|
|
219
|
-
const map = new Map(scopeValuePairs);
|
|
220
|
-
return (scope) => {
|
|
221
|
-
if (map.has(scope)) return map.get(scope);
|
|
222
|
-
return readScope(scope);
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
function delayUnmount(mount, ms = 0) {
|
|
226
|
-
return () => {
|
|
227
|
-
const unmount = mount();
|
|
228
|
-
return () => setTimeout(unmount, ms);
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
var Bunja = class Bunja {
|
|
232
|
-
static counter = 0;
|
|
233
|
-
id = String(Bunja.counter++);
|
|
234
|
-
debugLabel = "";
|
|
235
|
-
#phase = {
|
|
236
|
-
baked: false,
|
|
237
|
-
parents: /* @__PURE__ */ new Set(),
|
|
238
|
-
scopes: /* @__PURE__ */ new Set()
|
|
239
|
-
};
|
|
240
|
-
constructor(init) {
|
|
241
|
-
this.init = init;
|
|
242
|
-
if (__DEV__) {
|
|
243
|
-
devtoolsGlobalHook.bunjas[this.id] = this;
|
|
244
|
-
devtoolsGlobalHook.emit("bunjaCreated", { bunjaId: this.id });
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
get baked() {
|
|
248
|
-
return this.#phase.baked;
|
|
249
|
-
}
|
|
250
|
-
get parents() {
|
|
251
|
-
if (this.#phase.baked) return this.#phase.parents;
|
|
252
|
-
return Array.from(this.#phase.parents);
|
|
253
|
-
}
|
|
254
|
-
get relatedBunjas() {
|
|
255
|
-
if (!this.#phase.baked) throw new Error("Bunja is not baked yet.");
|
|
256
|
-
return this.#phase.relatedBunjas;
|
|
257
|
-
}
|
|
258
|
-
get relatedScopes() {
|
|
259
|
-
if (!this.#phase.baked) throw new Error("Bunja is not baked yet.");
|
|
260
|
-
return this.#phase.relatedScopes;
|
|
261
|
-
}
|
|
262
|
-
addParent(bunja$1) {
|
|
263
|
-
if (this.#phase.baked) return;
|
|
264
|
-
this.#phase.parents.add(bunja$1);
|
|
265
|
-
}
|
|
266
|
-
addScope(scope) {
|
|
267
|
-
if (this.#phase.baked) return;
|
|
268
|
-
this.#phase.scopes.add(scope);
|
|
269
|
-
}
|
|
270
|
-
bake() {
|
|
271
|
-
if (this.#phase.baked) throw new Error("Bunja is already baked.");
|
|
272
|
-
const scopes = this.#phase.scopes;
|
|
273
|
-
const parents = this.parents;
|
|
274
|
-
const relatedBunjas = toposort(parents);
|
|
275
|
-
this.#phase = {
|
|
276
|
-
baked: true,
|
|
277
|
-
parents,
|
|
278
|
-
relatedBunjas,
|
|
279
|
-
relatedScopes: Array.from(new Set([...relatedBunjas.flatMap((bunja$1) => bunja$1.relatedScopes), ...scopes]))
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
calcInstanceId(scopeInstanceMap) {
|
|
283
|
-
const scopeInstanceIds = this.relatedScopes.map((scope) => scopeInstanceMap.get(scope).id);
|
|
284
|
-
return `${this.id}:${scopeInstanceIds.join(",")}`;
|
|
285
|
-
}
|
|
286
|
-
toString() {
|
|
287
|
-
const { id, debugLabel } = this;
|
|
288
|
-
return `[Bunja:${id}${debugLabel && ` - ${debugLabel}`}]`;
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
var Scope = class Scope {
|
|
292
|
-
static counter = 0;
|
|
293
|
-
id = String(Scope.counter++);
|
|
294
|
-
debugLabel = "";
|
|
295
|
-
constructor(hash = Scope.identity) {
|
|
296
|
-
this.hash = hash;
|
|
297
|
-
if (__DEV__) {
|
|
298
|
-
devtoolsGlobalHook.scopes[this.id] = this;
|
|
299
|
-
devtoolsGlobalHook.emit("scopeCreated", { scopeId: this.id });
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
static identity(x) {
|
|
303
|
-
return x;
|
|
304
|
-
}
|
|
305
|
-
bind(value) {
|
|
306
|
-
return [this, value];
|
|
307
|
-
}
|
|
308
|
-
toString() {
|
|
309
|
-
const { id, debugLabel } = this;
|
|
310
|
-
return `[Scope:${id}${debugLabel && ` - ${debugLabel}`}]`;
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
var RefCounter = class {
|
|
314
|
-
#count = 0;
|
|
315
|
-
add() {
|
|
316
|
-
++this.#count;
|
|
317
|
-
}
|
|
318
|
-
sub() {
|
|
319
|
-
--this.#count;
|
|
320
|
-
if (this.#count < 1) {
|
|
321
|
-
this.dispose();
|
|
322
|
-
this.dispose = noop;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
var BunjaInstance = class extends RefCounter {
|
|
327
|
-
#cleanup;
|
|
328
|
-
constructor(id, value, effect, _dispose) {
|
|
329
|
-
super();
|
|
330
|
-
this.id = id;
|
|
331
|
-
this.value = value;
|
|
332
|
-
this.effect = effect;
|
|
333
|
-
this._dispose = _dispose;
|
|
334
|
-
}
|
|
335
|
-
dispose() {
|
|
336
|
-
this.#cleanup?.();
|
|
337
|
-
this._dispose();
|
|
338
|
-
}
|
|
339
|
-
add() {
|
|
340
|
-
this.#cleanup ??= this.effect() ?? noop;
|
|
341
|
-
super.add();
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
var ScopeInstance = class ScopeInstance extends RefCounter {
|
|
345
|
-
static counter = 0;
|
|
346
|
-
id = String(ScopeInstance.counter++);
|
|
347
|
-
constructor(value, dispose) {
|
|
348
|
-
super();
|
|
349
|
-
this.value = value;
|
|
350
|
-
this.dispose = dispose;
|
|
351
|
-
}
|
|
352
|
-
};
|
|
353
|
-
function toposort(nodes) {
|
|
354
|
-
const visited = /* @__PURE__ */ new Set();
|
|
355
|
-
const result = [];
|
|
356
|
-
function visit(current) {
|
|
357
|
-
if (visited.has(current)) return;
|
|
358
|
-
visited.add(current);
|
|
359
|
-
for (const parent of current.parents) visit(parent);
|
|
360
|
-
result.push(current);
|
|
361
|
-
}
|
|
362
|
-
for (const node of nodes) visit(node);
|
|
363
|
-
return result;
|
|
364
|
-
}
|
|
365
|
-
const noop = () => {};
|
|
366
|
-
let devtoolsGlobalHook;
|
|
367
|
-
if (__DEV__) if (globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__) devtoolsGlobalHook = globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__;
|
|
368
|
-
else {
|
|
369
|
-
devtoolsGlobalHook = {
|
|
370
|
-
stores: {},
|
|
371
|
-
bunjas: {},
|
|
372
|
-
scopes: {},
|
|
373
|
-
listeners: {
|
|
374
|
-
bunjaCreated: /* @__PURE__ */ new Set(),
|
|
375
|
-
scopeCreated: /* @__PURE__ */ new Set(),
|
|
376
|
-
storeCreated: /* @__PURE__ */ new Set(),
|
|
377
|
-
storeDisposed: /* @__PURE__ */ new Set(),
|
|
378
|
-
getCalled: /* @__PURE__ */ new Set(),
|
|
379
|
-
bunjaInstanceMounted: /* @__PURE__ */ new Set(),
|
|
380
|
-
bunjaInstanceUnmounted: /* @__PURE__ */ new Set(),
|
|
381
|
-
scopeInstanceMounted: /* @__PURE__ */ new Set(),
|
|
382
|
-
scopeInstanceUnmounted: /* @__PURE__ */ new Set()
|
|
383
|
-
},
|
|
384
|
-
emit: (type, event) => {
|
|
385
|
-
for (const fn of devtoolsGlobalHook.listeners[type]) fn(event);
|
|
386
|
-
},
|
|
387
|
-
on: (type, listener) => {
|
|
388
|
-
devtoolsGlobalHook.listeners[type].add(listener);
|
|
389
|
-
return () => devtoolsGlobalHook.listeners[type].delete(listener);
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
|
-
globalThis.__BUNJA_DEVTOOLS_GLOBAL_HOOK__ = devtoolsGlobalHook;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
//#endregion
|
|
396
|
-
export { Bunja, BunjaStore, Scope, bunja, createBunjaStore, createReadScopeFn, createScope, delayUnmount };
|