tutuca 0.9.106 → 0.9.107
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/dist/tutuca-cli.js +113 -2
- package/dist/tutuca-components.js +130 -6
- package/dist/tutuca-dev.ext.js +114 -2
- package/dist/tutuca-dev.js +114 -2
- package/dist/tutuca-dev.min.js +2 -2
- package/dist/tutuca-extra.ext.js +117 -2
- package/dist/tutuca-extra.js +117 -2
- package/dist/tutuca-extra.min.js +2 -2
- package/dist/tutuca-storybook.js +44 -3
- package/dist/tutuca.ext.js +117 -2
- package/dist/tutuca.js +117 -2
- package/dist/tutuca.min.js +2 -2
- package/package.json +1 -1
- package/skill/tutuca-source/tutuca.ext.js +117 -2
package/dist/tutuca-cli.js
CHANGED
|
@@ -4248,6 +4248,9 @@ class Step {
|
|
|
4248
4248
|
pinKey(_v) {
|
|
4249
4249
|
return this;
|
|
4250
4250
|
}
|
|
4251
|
+
toKey() {
|
|
4252
|
+
return null;
|
|
4253
|
+
}
|
|
4251
4254
|
}
|
|
4252
4255
|
function warnRawDynStep(op, step) {
|
|
4253
4256
|
console.warn(`Path.${op} reached a DynStep: call toTransactionPath() first`, step);
|
|
@@ -4332,6 +4335,15 @@ class Path {
|
|
|
4332
4335
|
}
|
|
4333
4336
|
return out;
|
|
4334
4337
|
}
|
|
4338
|
+
toKeys() {
|
|
4339
|
+
const out = [];
|
|
4340
|
+
for (const step of this.steps) {
|
|
4341
|
+
const k = step.toKey();
|
|
4342
|
+
if (k !== null)
|
|
4343
|
+
out.push(k);
|
|
4344
|
+
}
|
|
4345
|
+
return out;
|
|
4346
|
+
}
|
|
4335
4347
|
setValue(root, v) {
|
|
4336
4348
|
const intermediates = new Array(this.steps.length);
|
|
4337
4349
|
let curVal = root;
|
|
@@ -4589,6 +4601,9 @@ var init_path = __esm(() => {
|
|
|
4589
4601
|
withKey(k) {
|
|
4590
4602
|
return new SeqStep(this.field, k);
|
|
4591
4603
|
}
|
|
4604
|
+
toKey() {
|
|
4605
|
+
return { field: this.field };
|
|
4606
|
+
}
|
|
4592
4607
|
};
|
|
4593
4608
|
SeqStep = class SeqStep extends Step {
|
|
4594
4609
|
constructor(field, key) {
|
|
@@ -4607,6 +4622,9 @@ var init_path = __esm(() => {
|
|
|
4607
4622
|
enterFrame(stack, _prev, next) {
|
|
4608
4623
|
return stack.enter(next, { key: this.key }, true);
|
|
4609
4624
|
}
|
|
4625
|
+
toKey() {
|
|
4626
|
+
return { field: this.field, key: this.key };
|
|
4627
|
+
}
|
|
4610
4628
|
};
|
|
4611
4629
|
SeqAccessStep = class SeqAccessStep extends Step {
|
|
4612
4630
|
constructor(seqField, keyField) {
|
|
@@ -4628,6 +4646,9 @@ var init_path = __esm(() => {
|
|
|
4628
4646
|
const key = v?.get(this.keyField, NONE);
|
|
4629
4647
|
return key === NONE ? this : new SeqStep(this.seqField, key);
|
|
4630
4648
|
}
|
|
4649
|
+
toKey() {
|
|
4650
|
+
return { field: this.seqField };
|
|
4651
|
+
}
|
|
4631
4652
|
};
|
|
4632
4653
|
EachBindStep = class EachBindStep extends Step {
|
|
4633
4654
|
constructor(iterInfo, key) {
|
|
@@ -15154,12 +15175,47 @@ class Transactor {
|
|
|
15154
15175
|
this.transactions = [];
|
|
15155
15176
|
this.state = new State2(rootValue);
|
|
15156
15177
|
this.onTransactionPushed = () => {};
|
|
15178
|
+
this._observers = [];
|
|
15157
15179
|
this._inflight = new Set;
|
|
15158
15180
|
}
|
|
15159
15181
|
pushTransaction(t) {
|
|
15160
15182
|
this.transactions.push(t);
|
|
15161
15183
|
this.onTransactionPushed(t);
|
|
15162
15184
|
}
|
|
15185
|
+
observe(cb) {
|
|
15186
|
+
this._observers.push(cb);
|
|
15187
|
+
return () => {
|
|
15188
|
+
const i = this._observers.indexOf(cb);
|
|
15189
|
+
if (i !== -1)
|
|
15190
|
+
this._observers.splice(i, 1);
|
|
15191
|
+
};
|
|
15192
|
+
}
|
|
15193
|
+
_emit(record) {
|
|
15194
|
+
for (const cb of this._observers)
|
|
15195
|
+
cb(record);
|
|
15196
|
+
}
|
|
15197
|
+
_emitTransaction(transaction, root) {
|
|
15198
|
+
if (this._observers.length === 0)
|
|
15199
|
+
return;
|
|
15200
|
+
if (transaction._resolvedHandler === undefined)
|
|
15201
|
+
return;
|
|
15202
|
+
const path = transaction.getTransactionPath().pinKeys(root);
|
|
15203
|
+
this._emit({
|
|
15204
|
+
kind: transaction.observeKind,
|
|
15205
|
+
name: transaction.observeName,
|
|
15206
|
+
args: transaction.args ?? null,
|
|
15207
|
+
path,
|
|
15208
|
+
pathKeys: path.toKeys(),
|
|
15209
|
+
targetPath: transaction.targetPath ?? transaction.path,
|
|
15210
|
+
handler: transaction._resolvedHandler ?? null,
|
|
15211
|
+
handlerName: transaction._resolvedHandler?.name || null,
|
|
15212
|
+
matched: transaction._matched ?? null,
|
|
15213
|
+
before: transaction._before,
|
|
15214
|
+
after: transaction._after,
|
|
15215
|
+
parent: transaction.parentTransaction,
|
|
15216
|
+
timestamp: Date.now()
|
|
15217
|
+
});
|
|
15218
|
+
}
|
|
15163
15219
|
_link(child, parent) {
|
|
15164
15220
|
if (parent) {
|
|
15165
15221
|
const release = parent.completion.track();
|
|
@@ -15210,7 +15266,26 @@ class Transactor {
|
|
|
15210
15266
|
const curRoot = this.state.val;
|
|
15211
15267
|
const txnPath = path.toTransactionPath();
|
|
15212
15268
|
const curLeaf = txnPath.lookup(curRoot);
|
|
15213
|
-
const
|
|
15269
|
+
const found = this.comps.getRequestFor(curLeaf, name);
|
|
15270
|
+
const handler = found ?? mkReq404(name);
|
|
15271
|
+
if (this._observers.length > 0) {
|
|
15272
|
+
const reqPath = txnPath.pinKeys(curRoot);
|
|
15273
|
+
this._emit({
|
|
15274
|
+
kind: "request",
|
|
15275
|
+
name,
|
|
15276
|
+
args,
|
|
15277
|
+
path: reqPath,
|
|
15278
|
+
pathKeys: reqPath.toKeys(),
|
|
15279
|
+
targetPath: path,
|
|
15280
|
+
handler: found?.fn ?? null,
|
|
15281
|
+
handlerName: found?.fn?.name || name,
|
|
15282
|
+
matched: found ? "exact" : "none",
|
|
15283
|
+
before: curLeaf,
|
|
15284
|
+
after: undefined,
|
|
15285
|
+
parent,
|
|
15286
|
+
timestamp: Date.now()
|
|
15287
|
+
});
|
|
15288
|
+
}
|
|
15214
15289
|
const reqCtx = new RequestContext(path, this, parent, curRoot);
|
|
15215
15290
|
const resHandlerName = opts?.onResName ?? name;
|
|
15216
15291
|
const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
|
|
@@ -15245,6 +15320,7 @@ class Transactor {
|
|
|
15245
15320
|
if (newState !== undefined) {
|
|
15246
15321
|
this.state.set(newState, { transaction });
|
|
15247
15322
|
transaction.afterTransaction();
|
|
15323
|
+
this._emitTransaction(transaction, curState);
|
|
15248
15324
|
} else
|
|
15249
15325
|
console.warn("undefined new state", { curState, transaction });
|
|
15250
15326
|
} finally {
|
|
@@ -15293,8 +15369,15 @@ class Transaction {
|
|
|
15293
15369
|
buildStack(root, comps) {
|
|
15294
15370
|
return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
|
|
15295
15371
|
}
|
|
15372
|
+
get observeKind() {
|
|
15373
|
+
return null;
|
|
15374
|
+
}
|
|
15375
|
+
get observeName() {
|
|
15376
|
+
return null;
|
|
15377
|
+
}
|
|
15296
15378
|
callHandler(root, instance, comps) {
|
|
15297
15379
|
const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
|
|
15380
|
+
this._resolvedHandler = handler;
|
|
15298
15381
|
return handler.apply(instance, args);
|
|
15299
15382
|
}
|
|
15300
15383
|
getHandlerAndArgs(_root, _instance, _comps) {
|
|
@@ -15307,6 +15390,8 @@ class Transaction {
|
|
|
15307
15390
|
const txnPath = this.getTransactionPath();
|
|
15308
15391
|
const curLeaf = txnPath.lookup(curRoot);
|
|
15309
15392
|
const newLeaf = this.callHandler(curRoot, curLeaf, comps);
|
|
15393
|
+
this._before = curLeaf;
|
|
15394
|
+
this._after = newLeaf;
|
|
15310
15395
|
this._completion?.markSelfSettled({ value: newLeaf, old: curLeaf });
|
|
15311
15396
|
return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
|
|
15312
15397
|
}
|
|
@@ -15442,6 +15527,12 @@ var init_transactor = __esm(() => {
|
|
|
15442
15527
|
this._dispatchPath ??= this.path.compact();
|
|
15443
15528
|
return this._dispatchPath;
|
|
15444
15529
|
}
|
|
15530
|
+
get observeKind() {
|
|
15531
|
+
return "input";
|
|
15532
|
+
}
|
|
15533
|
+
get observeName() {
|
|
15534
|
+
return this.e?.type ?? null;
|
|
15535
|
+
}
|
|
15445
15536
|
buildRootStack(root, comps) {
|
|
15446
15537
|
return Stack2.root(comps, root, this);
|
|
15447
15538
|
}
|
|
@@ -15510,9 +15601,26 @@ var init_transactor = __esm(() => {
|
|
|
15510
15601
|
this.targetPath = path;
|
|
15511
15602
|
}
|
|
15512
15603
|
handlerProp = null;
|
|
15604
|
+
get observeKind() {
|
|
15605
|
+
return this.handlerProp;
|
|
15606
|
+
}
|
|
15607
|
+
get observeName() {
|
|
15608
|
+
return this.name;
|
|
15609
|
+
}
|
|
15513
15610
|
getHandlerForName(comp) {
|
|
15514
15611
|
const handlers = comp?.[this.handlerProp];
|
|
15515
|
-
|
|
15612
|
+
const exact = handlers?.[this.name];
|
|
15613
|
+
if (exact) {
|
|
15614
|
+
this._matched = "exact";
|
|
15615
|
+
return exact;
|
|
15616
|
+
}
|
|
15617
|
+
const unknown = handlers?.$unknown;
|
|
15618
|
+
if (unknown) {
|
|
15619
|
+
this._matched = "unknown";
|
|
15620
|
+
return unknown;
|
|
15621
|
+
}
|
|
15622
|
+
this._matched = "none";
|
|
15623
|
+
return nullHandler;
|
|
15516
15624
|
}
|
|
15517
15625
|
getHandlerAndArgs(_root, instance, comps) {
|
|
15518
15626
|
const handler = this.getHandlerForName(comps.getCompFor(instance));
|
|
@@ -15722,6 +15830,9 @@ class App {
|
|
|
15722
15830
|
onChange(callback) {
|
|
15723
15831
|
this.transactor.state.onChange(callback);
|
|
15724
15832
|
}
|
|
15833
|
+
observe(callback) {
|
|
15834
|
+
return this.transactor.observe(callback);
|
|
15835
|
+
}
|
|
15725
15836
|
compile() {
|
|
15726
15837
|
for (const Comp of this.comps.byId.values()) {
|
|
15727
15838
|
Comp.compile(this.ParseContext);
|
|
@@ -1402,6 +1402,12 @@ function getComponents4() {
|
|
|
1402
1402
|
];
|
|
1403
1403
|
}
|
|
1404
1404
|
|
|
1405
|
+
// src/components/tutuca/activity-inspector.js
|
|
1406
|
+
import { component as component9, html as html9 } from "tutuca";
|
|
1407
|
+
|
|
1408
|
+
// src/components/tutuca/instance-inspector.js
|
|
1409
|
+
import { component as component8, html as html8, isRecord } from "tutuca";
|
|
1410
|
+
|
|
1405
1411
|
// src/components/tutuca/component-inspector.js
|
|
1406
1412
|
import { component as component5, html as html5 } from "tutuca";
|
|
1407
1413
|
function introspectComponent(comp) {
|
|
@@ -1579,9 +1585,6 @@ function getComponents5() {
|
|
|
1579
1585
|
return [ComponentInspector, CompSection, CompField, CompName, CompView, ...getComponents2()];
|
|
1580
1586
|
}
|
|
1581
1587
|
|
|
1582
|
-
// src/components/tutuca/instance-inspector.js
|
|
1583
|
-
import { component as component8, html as html8, isRecord } from "tutuca";
|
|
1584
|
-
|
|
1585
1588
|
// src/components/tutuca/lint-inspector.js
|
|
1586
1589
|
import { component as component6, html as html6 } from "tutuca";
|
|
1587
1590
|
var tagDisplay = (tag) => tag ? String(tag).toLowerCase() : "";
|
|
@@ -2235,6 +2238,120 @@ function getComponents8() {
|
|
|
2235
2238
|
});
|
|
2236
2239
|
}
|
|
2237
2240
|
|
|
2241
|
+
// src/components/tutuca/activity-inspector.js
|
|
2242
|
+
var ACTIVITY_CAP = 50;
|
|
2243
|
+
var ActivityEntry = component9({
|
|
2244
|
+
name: "ActivityEntry",
|
|
2245
|
+
fields: {
|
|
2246
|
+
kind: "",
|
|
2247
|
+
name: "",
|
|
2248
|
+
handlerName: "",
|
|
2249
|
+
matched: "",
|
|
2250
|
+
pathLabel: "",
|
|
2251
|
+
time: "",
|
|
2252
|
+
before: null,
|
|
2253
|
+
after: null,
|
|
2254
|
+
hasAfter: true
|
|
2255
|
+
},
|
|
2256
|
+
view: html9`<div
|
|
2257
|
+
class="rounded border border-base-content/15 p-2 text-sm flex flex-col gap-1"
|
|
2258
|
+
>
|
|
2259
|
+
<div class="flex items-center gap-2 flex-wrap">
|
|
2260
|
+
<span
|
|
2261
|
+
title="How this was dispatched: receive (send), bubble, response, input, or request"
|
|
2262
|
+
class="badge badge-sm badge-neutral"
|
|
2263
|
+
@text=".kind"
|
|
2264
|
+
></span>
|
|
2265
|
+
<span
|
|
2266
|
+
title="Message name dispatched — for a DOM input, the event type (click, input, change, keydown, …)"
|
|
2267
|
+
class="font-mono font-semibold"
|
|
2268
|
+
@text=".name"
|
|
2269
|
+
></span>
|
|
2270
|
+
<span
|
|
2271
|
+
title="Actual handler that ran — shown only when it differs from the name (e.g. a $unknown fallback)"
|
|
2272
|
+
class="text-xs opacity-60 font-mono"
|
|
2273
|
+
@show="truthy? .handlerName"
|
|
2274
|
+
@text=".handlerName"
|
|
2275
|
+
></span>
|
|
2276
|
+
<span
|
|
2277
|
+
title="Path to the target component"
|
|
2278
|
+
class="text-xs opacity-40 font-mono"
|
|
2279
|
+
@text=".pathLabel"
|
|
2280
|
+
></span>
|
|
2281
|
+
<span
|
|
2282
|
+
title="Handler resolution — exact: matched by name · unknown: $unknown fallback · none: no handler (no-op)"
|
|
2283
|
+
class="badge badge-xs badge-ghost"
|
|
2284
|
+
@show="truthy? .matched"
|
|
2285
|
+
@text=".matched"
|
|
2286
|
+
></span>
|
|
2287
|
+
<span
|
|
2288
|
+
title="Time this event ran (HH:MM:SS.mmm)"
|
|
2289
|
+
class="ml-auto text-xs opacity-40 font-mono tabular-nums"
|
|
2290
|
+
@text=".time"
|
|
2291
|
+
></span>
|
|
2292
|
+
</div>
|
|
2293
|
+
<div class="flex gap-3 items-start font-mono text-xs">
|
|
2294
|
+
<div class="flex-1 min-w-0">
|
|
2295
|
+
<div class="opacity-50" title="Target state before the handler ran">before</div>
|
|
2296
|
+
<x render=".before"></x>
|
|
2297
|
+
</div>
|
|
2298
|
+
<div class="flex-1 min-w-0" @show=".hasAfter">
|
|
2299
|
+
<div class="opacity-50" title="Target state after the handler ran">after</div>
|
|
2300
|
+
<x render=".after"></x>
|
|
2301
|
+
</div>
|
|
2302
|
+
</div>
|
|
2303
|
+
</div>`
|
|
2304
|
+
});
|
|
2305
|
+
var ActivityLog = component9({
|
|
2306
|
+
name: "ActivityLog",
|
|
2307
|
+
fields: { events: [], hasEvents: false },
|
|
2308
|
+
methods: {
|
|
2309
|
+
appendEntry(entry) {
|
|
2310
|
+
return this.setEvents(this.events.unshift(entry).slice(0, ACTIVITY_CAP)).setHasEvents(true);
|
|
2311
|
+
}
|
|
2312
|
+
},
|
|
2313
|
+
view: html9`<div class="p-3 flex flex-col gap-2 max-h-[60vh] overflow-y-auto">
|
|
2314
|
+
<div class="text-xs opacity-40" @hide=".hasEvents">
|
|
2315
|
+
No activity yet — interact with the component.
|
|
2316
|
+
</div>
|
|
2317
|
+
<x render-each=".events"></x>
|
|
2318
|
+
</div>`
|
|
2319
|
+
});
|
|
2320
|
+
function fmtActivityTime(ts) {
|
|
2321
|
+
const d = new Date(ts);
|
|
2322
|
+
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
2323
|
+
return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;
|
|
2324
|
+
}
|
|
2325
|
+
function pathKeysLabel(pathKeys) {
|
|
2326
|
+
return pathKeys.map((k) => k.key === undefined ? k.field : `${k.field}[${k.key}]`).join(".");
|
|
2327
|
+
}
|
|
2328
|
+
function makeInspect(app) {
|
|
2329
|
+
return (value) => {
|
|
2330
|
+
const comp = isComponentInstance(value) ? app.comps.getCompFor(value) : null;
|
|
2331
|
+
return InstanceInspector.Class.fromData(value, comp);
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
function recordToEntry(record, { inspect, pathLabel = pathKeysLabel } = {}) {
|
|
2335
|
+
const hasAfter = record.after !== undefined;
|
|
2336
|
+
const primary = record.name ?? record.handlerName ?? "?";
|
|
2337
|
+
const handler = record.handlerName ?? "";
|
|
2338
|
+
const handlerLabel = handler && handler !== primary ? `→ ${handler}` : "";
|
|
2339
|
+
return ActivityEntry.make({
|
|
2340
|
+
kind: record.kind ?? "",
|
|
2341
|
+
name: primary,
|
|
2342
|
+
handlerName: handlerLabel,
|
|
2343
|
+
matched: record.matched ?? "",
|
|
2344
|
+
pathLabel: pathLabel(record.pathKeys),
|
|
2345
|
+
time: fmtActivityTime(record.timestamp),
|
|
2346
|
+
before: inspect(record.before),
|
|
2347
|
+
after: hasAfter ? inspect(record.after) : null,
|
|
2348
|
+
hasAfter
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
function getComponents9() {
|
|
2352
|
+
return [ActivityLog, ActivityEntry];
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2238
2355
|
// src/components/build-views.js
|
|
2239
2356
|
async function buildInspectorViews(value, scope, { getTests = null, components = [], dev = null, name } = {}) {
|
|
2240
2357
|
const comp = isComponentInstance(value) ? scope.getCompFor(value) : null;
|
|
@@ -2273,8 +2390,9 @@ async function buildInspectorViews(value, scope, { getTests = null, components =
|
|
|
2273
2390
|
}
|
|
2274
2391
|
|
|
2275
2392
|
// src/components/index.js
|
|
2276
|
-
function
|
|
2393
|
+
function getComponents10() {
|
|
2277
2394
|
const all = [
|
|
2395
|
+
...getComponents9(),
|
|
2278
2396
|
...getComponents5(),
|
|
2279
2397
|
...getComponents8(),
|
|
2280
2398
|
...getComponents6(),
|
|
@@ -2294,13 +2412,17 @@ function getComponents9() {
|
|
|
2294
2412
|
}
|
|
2295
2413
|
export {
|
|
2296
2414
|
valueWrapperMethods,
|
|
2415
|
+
recordToEntry,
|
|
2416
|
+
pathKeysLabel,
|
|
2297
2417
|
makeValueInspector,
|
|
2418
|
+
makeInspect,
|
|
2298
2419
|
makeCompositeView,
|
|
2299
2420
|
lintMessage,
|
|
2300
2421
|
isComponentInstance,
|
|
2301
2422
|
introspectComponent,
|
|
2302
|
-
|
|
2423
|
+
getComponents10 as getComponents,
|
|
2303
2424
|
fmtAnyKey,
|
|
2425
|
+
fmtActivityTime,
|
|
2304
2426
|
compositeView,
|
|
2305
2427
|
compositeMethods,
|
|
2306
2428
|
compositeFields,
|
|
@@ -2369,5 +2491,7 @@ export {
|
|
|
2369
2491
|
CompView,
|
|
2370
2492
|
CompSection,
|
|
2371
2493
|
CompName,
|
|
2372
|
-
CompField
|
|
2494
|
+
CompField,
|
|
2495
|
+
ActivityLog,
|
|
2496
|
+
ActivityEntry
|
|
2373
2497
|
};
|
package/dist/tutuca-dev.ext.js
CHANGED
|
@@ -117,6 +117,9 @@ class Step {
|
|
|
117
117
|
pinKey(_v) {
|
|
118
118
|
return this;
|
|
119
119
|
}
|
|
120
|
+
toKey() {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
class BindStep extends Step {
|
|
@@ -178,6 +181,9 @@ class FieldStep extends Step {
|
|
|
178
181
|
withKey(k) {
|
|
179
182
|
return new SeqStep(this.field, k);
|
|
180
183
|
}
|
|
184
|
+
toKey() {
|
|
185
|
+
return { field: this.field };
|
|
186
|
+
}
|
|
181
187
|
}
|
|
182
188
|
|
|
183
189
|
class SeqStep extends Step {
|
|
@@ -197,6 +203,9 @@ class SeqStep extends Step {
|
|
|
197
203
|
enterFrame(stack, _prev, next) {
|
|
198
204
|
return stack.enter(next, { key: this.key }, true);
|
|
199
205
|
}
|
|
206
|
+
toKey() {
|
|
207
|
+
return { field: this.field, key: this.key };
|
|
208
|
+
}
|
|
200
209
|
}
|
|
201
210
|
|
|
202
211
|
class SeqAccessStep extends Step {
|
|
@@ -219,6 +228,9 @@ class SeqAccessStep extends Step {
|
|
|
219
228
|
const key = v?.get(this.keyField, NONE);
|
|
220
229
|
return key === NONE ? this : new SeqStep(this.seqField, key);
|
|
221
230
|
}
|
|
231
|
+
toKey() {
|
|
232
|
+
return { field: this.seqField };
|
|
233
|
+
}
|
|
222
234
|
}
|
|
223
235
|
|
|
224
236
|
class EachBindStep extends Step {
|
|
@@ -374,6 +386,15 @@ class Path {
|
|
|
374
386
|
}
|
|
375
387
|
return out;
|
|
376
388
|
}
|
|
389
|
+
toKeys() {
|
|
390
|
+
const out = [];
|
|
391
|
+
for (const step of this.steps) {
|
|
392
|
+
const k = step.toKey();
|
|
393
|
+
if (k !== null)
|
|
394
|
+
out.push(k);
|
|
395
|
+
}
|
|
396
|
+
return out;
|
|
397
|
+
}
|
|
377
398
|
setValue(root, v) {
|
|
378
399
|
const intermediates = new Array(this.steps.length);
|
|
379
400
|
let curVal = root;
|
|
@@ -6285,12 +6306,47 @@ class Transactor {
|
|
|
6285
6306
|
this.transactions = [];
|
|
6286
6307
|
this.state = new State2(rootValue);
|
|
6287
6308
|
this.onTransactionPushed = () => {};
|
|
6309
|
+
this._observers = [];
|
|
6288
6310
|
this._inflight = new Set;
|
|
6289
6311
|
}
|
|
6290
6312
|
pushTransaction(t) {
|
|
6291
6313
|
this.transactions.push(t);
|
|
6292
6314
|
this.onTransactionPushed(t);
|
|
6293
6315
|
}
|
|
6316
|
+
observe(cb) {
|
|
6317
|
+
this._observers.push(cb);
|
|
6318
|
+
return () => {
|
|
6319
|
+
const i = this._observers.indexOf(cb);
|
|
6320
|
+
if (i !== -1)
|
|
6321
|
+
this._observers.splice(i, 1);
|
|
6322
|
+
};
|
|
6323
|
+
}
|
|
6324
|
+
_emit(record) {
|
|
6325
|
+
for (const cb of this._observers)
|
|
6326
|
+
cb(record);
|
|
6327
|
+
}
|
|
6328
|
+
_emitTransaction(transaction, root) {
|
|
6329
|
+
if (this._observers.length === 0)
|
|
6330
|
+
return;
|
|
6331
|
+
if (transaction._resolvedHandler === undefined)
|
|
6332
|
+
return;
|
|
6333
|
+
const path = transaction.getTransactionPath().pinKeys(root);
|
|
6334
|
+
this._emit({
|
|
6335
|
+
kind: transaction.observeKind,
|
|
6336
|
+
name: transaction.observeName,
|
|
6337
|
+
args: transaction.args ?? null,
|
|
6338
|
+
path,
|
|
6339
|
+
pathKeys: path.toKeys(),
|
|
6340
|
+
targetPath: transaction.targetPath ?? transaction.path,
|
|
6341
|
+
handler: transaction._resolvedHandler ?? null,
|
|
6342
|
+
handlerName: transaction._resolvedHandler?.name || null,
|
|
6343
|
+
matched: transaction._matched ?? null,
|
|
6344
|
+
before: transaction._before,
|
|
6345
|
+
after: transaction._after,
|
|
6346
|
+
parent: transaction.parentTransaction,
|
|
6347
|
+
timestamp: Date.now()
|
|
6348
|
+
});
|
|
6349
|
+
}
|
|
6294
6350
|
_link(child, parent) {
|
|
6295
6351
|
if (parent) {
|
|
6296
6352
|
const release = parent.completion.track();
|
|
@@ -6341,7 +6397,26 @@ class Transactor {
|
|
|
6341
6397
|
const curRoot = this.state.val;
|
|
6342
6398
|
const txnPath = path.toTransactionPath();
|
|
6343
6399
|
const curLeaf = txnPath.lookup(curRoot);
|
|
6344
|
-
const
|
|
6400
|
+
const found = this.comps.getRequestFor(curLeaf, name);
|
|
6401
|
+
const handler = found ?? mkReq404(name);
|
|
6402
|
+
if (this._observers.length > 0) {
|
|
6403
|
+
const reqPath = txnPath.pinKeys(curRoot);
|
|
6404
|
+
this._emit({
|
|
6405
|
+
kind: "request",
|
|
6406
|
+
name,
|
|
6407
|
+
args,
|
|
6408
|
+
path: reqPath,
|
|
6409
|
+
pathKeys: reqPath.toKeys(),
|
|
6410
|
+
targetPath: path,
|
|
6411
|
+
handler: found?.fn ?? null,
|
|
6412
|
+
handlerName: found?.fn?.name || name,
|
|
6413
|
+
matched: found ? "exact" : "none",
|
|
6414
|
+
before: curLeaf,
|
|
6415
|
+
after: undefined,
|
|
6416
|
+
parent,
|
|
6417
|
+
timestamp: Date.now()
|
|
6418
|
+
});
|
|
6419
|
+
}
|
|
6345
6420
|
const reqCtx = new RequestContext(path, this, parent, curRoot);
|
|
6346
6421
|
const resHandlerName = opts?.onResName ?? name;
|
|
6347
6422
|
const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
|
|
@@ -6376,6 +6451,7 @@ class Transactor {
|
|
|
6376
6451
|
if (newState !== undefined) {
|
|
6377
6452
|
this.state.set(newState, { transaction });
|
|
6378
6453
|
transaction.afterTransaction();
|
|
6454
|
+
this._emitTransaction(transaction, curState);
|
|
6379
6455
|
} else
|
|
6380
6456
|
console.warn("undefined new state", { curState, transaction });
|
|
6381
6457
|
} finally {
|
|
@@ -6424,8 +6500,15 @@ class Transaction {
|
|
|
6424
6500
|
buildStack(root, comps) {
|
|
6425
6501
|
return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
|
|
6426
6502
|
}
|
|
6503
|
+
get observeKind() {
|
|
6504
|
+
return null;
|
|
6505
|
+
}
|
|
6506
|
+
get observeName() {
|
|
6507
|
+
return null;
|
|
6508
|
+
}
|
|
6427
6509
|
callHandler(root, instance, comps) {
|
|
6428
6510
|
const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
|
|
6511
|
+
this._resolvedHandler = handler;
|
|
6429
6512
|
return handler.apply(instance, args);
|
|
6430
6513
|
}
|
|
6431
6514
|
getHandlerAndArgs(_root, _instance, _comps) {
|
|
@@ -6438,6 +6521,8 @@ class Transaction {
|
|
|
6438
6521
|
const txnPath = this.getTransactionPath();
|
|
6439
6522
|
const curLeaf = txnPath.lookup(curRoot);
|
|
6440
6523
|
const newLeaf = this.callHandler(curRoot, curLeaf, comps);
|
|
6524
|
+
this._before = curLeaf;
|
|
6525
|
+
this._after = newLeaf;
|
|
6441
6526
|
this._completion?.markSelfSettled({ value: newLeaf, old: curLeaf });
|
|
6442
6527
|
return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
|
|
6443
6528
|
}
|
|
@@ -6462,6 +6547,12 @@ class InputEvent extends Transaction {
|
|
|
6462
6547
|
this._dispatchPath ??= this.path.compact();
|
|
6463
6548
|
return this._dispatchPath;
|
|
6464
6549
|
}
|
|
6550
|
+
get observeKind() {
|
|
6551
|
+
return "input";
|
|
6552
|
+
}
|
|
6553
|
+
get observeName() {
|
|
6554
|
+
return this.e?.type ?? null;
|
|
6555
|
+
}
|
|
6465
6556
|
buildRootStack(root, comps) {
|
|
6466
6557
|
return Stack.root(comps, root, this);
|
|
6467
6558
|
}
|
|
@@ -6531,9 +6622,26 @@ class NameArgsTransaction extends Transaction {
|
|
|
6531
6622
|
this.targetPath = path;
|
|
6532
6623
|
}
|
|
6533
6624
|
handlerProp = null;
|
|
6625
|
+
get observeKind() {
|
|
6626
|
+
return this.handlerProp;
|
|
6627
|
+
}
|
|
6628
|
+
get observeName() {
|
|
6629
|
+
return this.name;
|
|
6630
|
+
}
|
|
6534
6631
|
getHandlerForName(comp) {
|
|
6535
6632
|
const handlers = comp?.[this.handlerProp];
|
|
6536
|
-
|
|
6633
|
+
const exact = handlers?.[this.name];
|
|
6634
|
+
if (exact) {
|
|
6635
|
+
this._matched = "exact";
|
|
6636
|
+
return exact;
|
|
6637
|
+
}
|
|
6638
|
+
const unknown = handlers?.$unknown;
|
|
6639
|
+
if (unknown) {
|
|
6640
|
+
this._matched = "unknown";
|
|
6641
|
+
return unknown;
|
|
6642
|
+
}
|
|
6643
|
+
this._matched = "none";
|
|
6644
|
+
return nullHandler;
|
|
6537
6645
|
}
|
|
6538
6646
|
getHandlerAndArgs(_root, instance, comps) {
|
|
6539
6647
|
const handler = this.getHandlerForName(comps.getCompFor(instance));
|
|
@@ -7564,6 +7672,9 @@ class App {
|
|
|
7564
7672
|
onChange(callback) {
|
|
7565
7673
|
this.transactor.state.onChange(callback);
|
|
7566
7674
|
}
|
|
7675
|
+
observe(callback) {
|
|
7676
|
+
return this.transactor.observe(callback);
|
|
7677
|
+
}
|
|
7567
7678
|
compile() {
|
|
7568
7679
|
for (const Comp of this.comps.byId.values()) {
|
|
7569
7680
|
Comp.compile(this.ParseContext);
|
|
@@ -8467,6 +8578,7 @@ export {
|
|
|
8467
8578
|
setIn,
|
|
8468
8579
|
set,
|
|
8469
8580
|
runTests,
|
|
8581
|
+
rootDispatcher,
|
|
8470
8582
|
resolveArgs,
|
|
8471
8583
|
reportTestReportToConsole,
|
|
8472
8584
|
removeIn,
|