tutuca 0.9.93 → 0.9.95
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 +230 -59
- package/dist/tutuca-dev.ext.js +1367 -1200
- package/dist/tutuca-dev.js +1367 -1200
- package/dist/tutuca-dev.min.js +2 -2
- package/dist/tutuca-extra.ext.js +186 -52
- package/dist/tutuca-extra.js +187 -53
- package/dist/tutuca-extra.min.js +1 -1
- package/dist/tutuca-storybook.js +69 -11
- package/dist/tutuca.ext.js +186 -52
- package/dist/tutuca.js +187 -53
- package/dist/tutuca.min.js +1 -1
- package/package.json +2 -1
- package/skill/tutuca/core.md +19 -1
- package/skill/tutuca/patterns/coordinate-components.md +5 -0
- package/skill/tutuca/patterns/handle-events.md +7 -0
- package/skill/tutuca/storybook.md +46 -0
- package/skill/tutuca/testing.md +33 -0
- package/skill/tutuca-source/tutuca.ext.js +186 -52
package/dist/tutuca-cli.js
CHANGED
|
@@ -13933,36 +13933,81 @@ class Transactor {
|
|
|
13933
13933
|
this.transactions = [];
|
|
13934
13934
|
this.state = new State2(rootValue);
|
|
13935
13935
|
this.onTransactionPushed = () => {};
|
|
13936
|
+
this._inflight = new Set;
|
|
13936
13937
|
}
|
|
13937
13938
|
pushTransaction(t) {
|
|
13938
13939
|
this.transactions.push(t);
|
|
13939
13940
|
this.onTransactionPushed(t);
|
|
13940
13941
|
}
|
|
13942
|
+
_link(child, parent) {
|
|
13943
|
+
if (parent) {
|
|
13944
|
+
const release = parent.completion.track();
|
|
13945
|
+
child.completion.whenSubtreeSettled().then(release);
|
|
13946
|
+
}
|
|
13947
|
+
return child;
|
|
13948
|
+
}
|
|
13941
13949
|
pushSend(path, name, args = [], opts = {}, parent = null) {
|
|
13942
|
-
|
|
13950
|
+
const t = new SendEvent(path, this, name, args, parent, opts);
|
|
13951
|
+
this.pushTransaction(t);
|
|
13952
|
+
return this._link(t, parent);
|
|
13953
|
+
}
|
|
13954
|
+
pushInput(path, name, args = [], opts = {}, parent = null) {
|
|
13955
|
+
const t = new InputDispatchEvent(path, this, name, args, parent, opts);
|
|
13956
|
+
this.pushTransaction(t);
|
|
13957
|
+
return this._link(t, parent);
|
|
13943
13958
|
}
|
|
13944
13959
|
pushBubble(path, name, args = [], opts = {}, parent = null, targetPath = null) {
|
|
13945
13960
|
const newOpts = opts.skipSelf ? { ...opts, skipSelf: false } : opts;
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
const
|
|
13952
|
-
const
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
this.
|
|
13961
|
+
const t = new BubbleEvent(path, this, name, args, parent, newOpts, targetPath);
|
|
13962
|
+
this.pushTransaction(t);
|
|
13963
|
+
return this._link(t, parent);
|
|
13964
|
+
}
|
|
13965
|
+
pushRequest(path, name, args = [], opts = {}, parent = null) {
|
|
13966
|
+
const release = parent ? parent.completion.track() : null;
|
|
13967
|
+
const p = this._runRequest(path, name, args, opts, parent, release);
|
|
13968
|
+
this._inflight.add(p);
|
|
13969
|
+
p.finally(() => this._inflight.delete(p));
|
|
13970
|
+
return p;
|
|
13971
|
+
}
|
|
13972
|
+
async settle(maxTurns = 1e4) {
|
|
13973
|
+
while ((this.hasPendingTransactions || this._inflight.size) && maxTurns-- > 0) {
|
|
13974
|
+
while (this.hasPendingTransactions)
|
|
13975
|
+
this.transactNext();
|
|
13976
|
+
if (this._inflight.size)
|
|
13977
|
+
await Promise.allSettled([...this._inflight]);
|
|
13978
|
+
}
|
|
13979
|
+
}
|
|
13980
|
+
async _runRequest(path, name, args = [], opts = {}, parent = null, release = null) {
|
|
13981
|
+
let released = false;
|
|
13982
|
+
const transfer = (t) => {
|
|
13983
|
+
if (release) {
|
|
13984
|
+
released = true;
|
|
13985
|
+
t.completion.whenSubtreeSettled().then(release);
|
|
13986
|
+
}
|
|
13960
13987
|
};
|
|
13961
13988
|
try {
|
|
13962
|
-
const
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13989
|
+
const curRoot = this.state.val;
|
|
13990
|
+
const txnPath = path.toTransactionPath();
|
|
13991
|
+
const curLeaf = txnPath.lookup(curRoot);
|
|
13992
|
+
const handler = this.comps.getRequestFor(curLeaf, name) ?? mkReq404(name);
|
|
13993
|
+
const reqCtx = new RequestContext(path, this, parent, curRoot);
|
|
13994
|
+
const resHandlerName = opts?.onResName ?? name;
|
|
13995
|
+
const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
|
|
13996
|
+
const push = (specificName, baseName, singleArg, result, error) => {
|
|
13997
|
+
const resArgs = specificName ? [singleArg] : [result, error];
|
|
13998
|
+
const t = new ResponseEvent(path, this, specificName ?? baseName, resArgs, parent, resPath);
|
|
13999
|
+
transfer(t);
|
|
14000
|
+
this.pushTransaction(t);
|
|
14001
|
+
};
|
|
14002
|
+
try {
|
|
14003
|
+
const result = await handler.fn.apply(null, [...args, reqCtx]);
|
|
14004
|
+
push(opts?.onOkName, resHandlerName, result, result, null);
|
|
14005
|
+
} catch (error) {
|
|
14006
|
+
push(opts?.onErrorName, resHandlerName, error, null, error);
|
|
14007
|
+
}
|
|
14008
|
+
} finally {
|
|
14009
|
+
if (release && !released)
|
|
14010
|
+
release();
|
|
13966
14011
|
}
|
|
13967
14012
|
}
|
|
13968
14013
|
get hasPendingTransactions() {
|
|
@@ -13973,13 +14018,18 @@ class Transactor {
|
|
|
13973
14018
|
this.transact(this.transactions.shift());
|
|
13974
14019
|
}
|
|
13975
14020
|
transact(transaction) {
|
|
13976
|
-
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
|
|
13981
|
-
|
|
13982
|
-
|
|
14021
|
+
try {
|
|
14022
|
+
const curState = this.state.val;
|
|
14023
|
+
const newState = transaction.run(curState, this.comps);
|
|
14024
|
+
if (newState !== undefined) {
|
|
14025
|
+
this.state.set(newState, { transaction });
|
|
14026
|
+
transaction.afterTransaction();
|
|
14027
|
+
} else
|
|
14028
|
+
console.warn("undefined new state", { curState, transaction });
|
|
14029
|
+
} finally {
|
|
14030
|
+
transaction._completion?.ensureSelfSettled();
|
|
14031
|
+
transaction._completion?.releaseSelf();
|
|
14032
|
+
}
|
|
13983
14033
|
}
|
|
13984
14034
|
transactInputNow(path, event, eventHandler, dragInfo) {
|
|
13985
14035
|
this.transact(new InputEvent(path, event, eventHandler, this, dragInfo));
|
|
@@ -14000,18 +14050,17 @@ class Transaction {
|
|
|
14000
14050
|
this.path = path;
|
|
14001
14051
|
this.transactor = transactor;
|
|
14002
14052
|
this.parentTransaction = parentTransaction;
|
|
14003
|
-
this.
|
|
14053
|
+
this._completion = null;
|
|
14004
14054
|
}
|
|
14005
|
-
get
|
|
14006
|
-
this.
|
|
14007
|
-
return this.
|
|
14055
|
+
get completion() {
|
|
14056
|
+
this._completion ??= new Completion;
|
|
14057
|
+
return this._completion;
|
|
14008
14058
|
}
|
|
14009
|
-
|
|
14010
|
-
return this.
|
|
14059
|
+
whenSettled() {
|
|
14060
|
+
return this.completion.whenSettled();
|
|
14011
14061
|
}
|
|
14012
|
-
|
|
14013
|
-
this.
|
|
14014
|
-
parentTransaction.task.addDep(this.task);
|
|
14062
|
+
whenSubtreeSettled() {
|
|
14063
|
+
return this.completion.whenSubtreeSettled();
|
|
14015
14064
|
}
|
|
14016
14065
|
run(rootValue, comps) {
|
|
14017
14066
|
return this.updateRootValue(rootValue, comps);
|
|
@@ -14037,7 +14086,7 @@ class Transaction {
|
|
|
14037
14086
|
const txnPath = this.getTransactionPath();
|
|
14038
14087
|
const curLeaf = txnPath.lookup(curRoot);
|
|
14039
14088
|
const newLeaf = this.callHandler(curRoot, curLeaf, comps);
|
|
14040
|
-
this.
|
|
14089
|
+
this._completion?.markSelfSettled({ value: newLeaf, old: curLeaf });
|
|
14041
14090
|
return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
|
|
14042
14091
|
}
|
|
14043
14092
|
lookupName(_name) {
|
|
@@ -14048,29 +14097,65 @@ function getValue(e) {
|
|
|
14048
14097
|
return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
|
|
14049
14098
|
}
|
|
14050
14099
|
|
|
14051
|
-
class
|
|
14100
|
+
class Completion {
|
|
14052
14101
|
constructor() {
|
|
14053
|
-
this.
|
|
14054
|
-
this.
|
|
14055
|
-
this.
|
|
14056
|
-
|
|
14057
|
-
|
|
14102
|
+
this.val = undefined;
|
|
14103
|
+
this.selfSettled = false;
|
|
14104
|
+
this.subtreeSettled = false;
|
|
14105
|
+
this.pending = 1;
|
|
14106
|
+
this._selfResolve = null;
|
|
14107
|
+
this._selfPromise = null;
|
|
14108
|
+
this._subtreeResolve = null;
|
|
14109
|
+
this._subtreePromise = null;
|
|
14110
|
+
this._selfReleased = false;
|
|
14111
|
+
}
|
|
14112
|
+
whenSettled() {
|
|
14113
|
+
if (this.selfSettled)
|
|
14114
|
+
return Promise.resolve(this.val);
|
|
14115
|
+
this._selfPromise ??= new Promise((res) => {
|
|
14116
|
+
this._selfResolve = res;
|
|
14058
14117
|
});
|
|
14059
|
-
this.
|
|
14118
|
+
return this._selfPromise;
|
|
14060
14119
|
}
|
|
14061
|
-
|
|
14062
|
-
|
|
14063
|
-
|
|
14064
|
-
|
|
14120
|
+
whenSubtreeSettled() {
|
|
14121
|
+
if (this.subtreeSettled)
|
|
14122
|
+
return Promise.resolve(this.val);
|
|
14123
|
+
this._subtreePromise ??= new Promise((res) => {
|
|
14124
|
+
this._subtreeResolve = res;
|
|
14125
|
+
});
|
|
14126
|
+
return this._subtreePromise;
|
|
14065
14127
|
}
|
|
14066
|
-
|
|
14128
|
+
markSelfSettled(val) {
|
|
14129
|
+
if (this.selfSettled)
|
|
14130
|
+
return;
|
|
14131
|
+
this.selfSettled = true;
|
|
14067
14132
|
this.val = val;
|
|
14068
|
-
this.
|
|
14133
|
+
this._selfResolve?.(val);
|
|
14134
|
+
}
|
|
14135
|
+
ensureSelfSettled() {
|
|
14136
|
+
if (!this.selfSettled)
|
|
14137
|
+
this.markSelfSettled(this.val);
|
|
14138
|
+
}
|
|
14139
|
+
track() {
|
|
14140
|
+
this.pending++;
|
|
14141
|
+
let done = false;
|
|
14142
|
+
return () => {
|
|
14143
|
+
if (done)
|
|
14144
|
+
return;
|
|
14145
|
+
done = true;
|
|
14146
|
+
this._release();
|
|
14147
|
+
};
|
|
14148
|
+
}
|
|
14149
|
+
releaseSelf() {
|
|
14150
|
+
if (this._selfReleased)
|
|
14151
|
+
return;
|
|
14152
|
+
this._selfReleased = true;
|
|
14153
|
+
this._release();
|
|
14069
14154
|
}
|
|
14070
|
-
|
|
14071
|
-
if (this.
|
|
14072
|
-
this.
|
|
14073
|
-
this.
|
|
14155
|
+
_release() {
|
|
14156
|
+
if (--this.pending === 0) {
|
|
14157
|
+
this.subtreeSettled = true;
|
|
14158
|
+
this._subtreeResolve?.(this.val);
|
|
14074
14159
|
}
|
|
14075
14160
|
}
|
|
14076
14161
|
}
|
|
@@ -14109,11 +14194,17 @@ class Dispatcher {
|
|
|
14109
14194
|
requestAtPath(path, name, args, opts) {
|
|
14110
14195
|
return this.transactor.pushRequest(path, name, args, opts, this.parent);
|
|
14111
14196
|
}
|
|
14197
|
+
inputAtPath(path, name, args, opts) {
|
|
14198
|
+
return this.transactor.pushInput(path, name, args, opts, this.parent);
|
|
14199
|
+
}
|
|
14112
14200
|
lookupTypeFor(name, inst) {
|
|
14113
14201
|
return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
|
|
14114
14202
|
}
|
|
14115
14203
|
}
|
|
14116
|
-
|
|
14204
|
+
function rootDispatcher(transactor) {
|
|
14205
|
+
return new Dispatcher(new Path([]), transactor, null);
|
|
14206
|
+
}
|
|
14207
|
+
var toNullIfNaN = (v) => Number.isNaN(v) ? null : v, InputEvent, NameArgsTransaction, ResponseEvent, SendEvent, BubbleEvent, InputDispatchEvent, EventContext, RequestContext, PathChanges;
|
|
14117
14208
|
var init_transactor = __esm(() => {
|
|
14118
14209
|
init_path();
|
|
14119
14210
|
init_stack();
|
|
@@ -14238,6 +14329,9 @@ var init_transactor = __esm(() => {
|
|
|
14238
14329
|
this.opts.bubbles = false;
|
|
14239
14330
|
}
|
|
14240
14331
|
};
|
|
14332
|
+
InputDispatchEvent = class InputDispatchEvent extends NameArgsTransaction {
|
|
14333
|
+
handlerProp = "input";
|
|
14334
|
+
};
|
|
14241
14335
|
EventContext = class EventContext extends Dispatcher {
|
|
14242
14336
|
get name() {
|
|
14243
14337
|
return this.parent?.name ?? null;
|
|
@@ -14623,6 +14717,49 @@ var init_render2 = __esm(() => {
|
|
|
14623
14717
|
init_render();
|
|
14624
14718
|
});
|
|
14625
14719
|
|
|
14720
|
+
// src/on.js
|
|
14721
|
+
function phaseOps(phase) {
|
|
14722
|
+
const ops = [];
|
|
14723
|
+
for (const type3 of OP_KINDS)
|
|
14724
|
+
for (const a of phase[type3] ?? [])
|
|
14725
|
+
ops.push({ type: type3, ...a });
|
|
14726
|
+
for (const a of phase.do ?? [])
|
|
14727
|
+
ops.push(a);
|
|
14728
|
+
return ops;
|
|
14729
|
+
}
|
|
14730
|
+
function resolveArgs(args, self) {
|
|
14731
|
+
return typeof args === "function" ? args(self) ?? [] : args ?? [];
|
|
14732
|
+
}
|
|
14733
|
+
function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
14734
|
+
if (!phase)
|
|
14735
|
+
return;
|
|
14736
|
+
for (const op of phaseOps(phase)) {
|
|
14737
|
+
const args = resolveArgs(op.args, self);
|
|
14738
|
+
switch (op.type) {
|
|
14739
|
+
case "send":
|
|
14740
|
+
dispatcher.sendAtPath(targetPath, op.name, args, op.opts);
|
|
14741
|
+
break;
|
|
14742
|
+
case "bubble":
|
|
14743
|
+
dispatcher.sendAtPath(targetPath, op.name, args, {
|
|
14744
|
+
skipSelf: true,
|
|
14745
|
+
bubbles: true,
|
|
14746
|
+
...op.opts
|
|
14747
|
+
});
|
|
14748
|
+
break;
|
|
14749
|
+
case "request":
|
|
14750
|
+
dispatcher.requestAtPath(targetPath, op.name, args, op.opts);
|
|
14751
|
+
break;
|
|
14752
|
+
case "input":
|
|
14753
|
+
dispatcher.inputAtPath(targetPath, op.name, args, op.opts);
|
|
14754
|
+
break;
|
|
14755
|
+
}
|
|
14756
|
+
}
|
|
14757
|
+
}
|
|
14758
|
+
var OP_KINDS;
|
|
14759
|
+
var init_on = __esm(() => {
|
|
14760
|
+
OP_KINDS = ["send", "bubble", "request", "input"];
|
|
14761
|
+
});
|
|
14762
|
+
|
|
14626
14763
|
// tools/core/tests.js
|
|
14627
14764
|
class Describe {
|
|
14628
14765
|
constructor({ title, componentName = null, parent = null }) {
|
|
@@ -14755,6 +14892,26 @@ function captureError(e) {
|
|
|
14755
14892
|
out.actual = e.actual;
|
|
14756
14893
|
return out;
|
|
14757
14894
|
}
|
|
14895
|
+
function buildStack({ components = [], macros = null, requestHandlers = null } = {}) {
|
|
14896
|
+
const stack = new ComponentStack;
|
|
14897
|
+
stack.registerComponents(components);
|
|
14898
|
+
if (macros)
|
|
14899
|
+
stack.registerMacros(macros);
|
|
14900
|
+
if (requestHandlers)
|
|
14901
|
+
stack.registerRequestHandlers(requestHandlers);
|
|
14902
|
+
return stack;
|
|
14903
|
+
}
|
|
14904
|
+
async function driveStack(stack, value, phase, opts = {}) {
|
|
14905
|
+
const transactor = new Transactor(stack.comps, value);
|
|
14906
|
+
if (opts.onMessage)
|
|
14907
|
+
transactor.state.onChange(({ val, old, info }) => {
|
|
14908
|
+
const t = info?.transaction;
|
|
14909
|
+
opts.onMessage({ kind: t?.handlerProp ?? "input", name: t?.name, args: t?.args, path: t?.path }, old, val);
|
|
14910
|
+
});
|
|
14911
|
+
dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
|
|
14912
|
+
await transactor.settle();
|
|
14913
|
+
return transactor.state.val;
|
|
14914
|
+
}
|
|
14758
14915
|
async function runTests({
|
|
14759
14916
|
getTests,
|
|
14760
14917
|
components = [],
|
|
@@ -14762,7 +14919,9 @@ async function runTests({
|
|
|
14762
14919
|
expect: expect2,
|
|
14763
14920
|
name = null,
|
|
14764
14921
|
grep = null,
|
|
14765
|
-
bail = false
|
|
14922
|
+
bail = false,
|
|
14923
|
+
requestHandlers = null,
|
|
14924
|
+
macros = null
|
|
14766
14925
|
} = {}) {
|
|
14767
14926
|
const counts = { pass: 0, fail: 0, skip: 0, total: 0 };
|
|
14768
14927
|
if (typeof getTests !== "function") {
|
|
@@ -14774,7 +14933,10 @@ async function runTests({
|
|
|
14774
14933
|
throw new Error("runTests: expect must be provided (e.g. chai's expect)");
|
|
14775
14934
|
}
|
|
14776
14935
|
const { describe, test: test2, moduleTests } = makeCollector({ path, components });
|
|
14777
|
-
|
|
14936
|
+
let _stack = null;
|
|
14937
|
+
const getStack = () => _stack ??= buildStack({ components, macros, requestHandlers });
|
|
14938
|
+
const driveLocal = (value, phase, opts = {}) => driveStack(getStack(), value, phase, opts);
|
|
14939
|
+
await getTests({ describe, test: test2, expect: expect2, drive: driveLocal });
|
|
14778
14940
|
let bailed = false;
|
|
14779
14941
|
async function visit(node) {
|
|
14780
14942
|
if (node instanceof Test) {
|
|
@@ -14842,7 +15004,12 @@ async function runTests({
|
|
|
14842
15004
|
modules: [new ModuleTestReport({ path, suites: suiteResults, counts })]
|
|
14843
15005
|
});
|
|
14844
15006
|
}
|
|
14845
|
-
var init_test = () => {
|
|
15007
|
+
var init_test = __esm(() => {
|
|
15008
|
+
init_components();
|
|
15009
|
+
init_on();
|
|
15010
|
+
init_path();
|
|
15011
|
+
init_transactor();
|
|
15012
|
+
});
|
|
14846
15013
|
|
|
14847
15014
|
// tools/cli/commands/_registry.js
|
|
14848
15015
|
var exports__registry = {};
|
|
@@ -14930,7 +15097,9 @@ var init__registry = __esm(() => {
|
|
|
14930
15097
|
expect,
|
|
14931
15098
|
name: positionals[0] ?? null,
|
|
14932
15099
|
grep: values.grep ?? null,
|
|
14933
|
-
bail: values.bail ?? false
|
|
15100
|
+
bail: values.bail ?? false,
|
|
15101
|
+
requestHandlers: normalized.requestHandlers,
|
|
15102
|
+
macros: normalized.macros
|
|
14934
15103
|
}),
|
|
14935
15104
|
exitOn: (result) => result.hasFailures ? 4 : 0
|
|
14936
15105
|
}
|
|
@@ -15951,7 +16120,9 @@ async function runDevTests(projectDir, devModuleUrls) {
|
|
|
15951
16120
|
getTests: mod.getTests,
|
|
15952
16121
|
components: normalized.components,
|
|
15953
16122
|
path: abs,
|
|
15954
|
-
expect
|
|
16123
|
+
expect,
|
|
16124
|
+
requestHandlers: normalized.requestHandlers,
|
|
16125
|
+
macros: normalized.macros
|
|
15955
16126
|
});
|
|
15956
16127
|
const m = report.modules[0];
|
|
15957
16128
|
totalTests += m.counts.total;
|