@wildwinter/expr-editor 0.12.3 → 0.13.1
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/index.cjs +55 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +55 -11
- package/dist/index.js.map +1 -1
- package/dist/styles.css +10 -0
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -93,6 +93,16 @@ function findChoicePeer(ast, path) {
|
|
|
93
93
|
return other.kind === "scopedvar" ? { scope: other.scope, name: other.name } : null;
|
|
94
94
|
}
|
|
95
95
|
var findEnumPeer = findChoicePeer;
|
|
96
|
+
var normaliseRef = (ref, defaultScope) => {
|
|
97
|
+
const low = ref.toLowerCase();
|
|
98
|
+
const prefix = `@${defaultScope.toLowerCase()}.`;
|
|
99
|
+
return low.startsWith(prefix) ? `@${low.slice(prefix.length)}` : low;
|
|
100
|
+
};
|
|
101
|
+
function advancedRef(node, defaultScope) {
|
|
102
|
+
if (node.kind !== "call" || node.name !== "advance" || node.args.length !== 1) return null;
|
|
103
|
+
const arg = node.args[0];
|
|
104
|
+
return arg.kind === "scopedvar" ? normaliseRef(`@${arg.scope}.${arg.name}`, defaultScope) : null;
|
|
105
|
+
}
|
|
96
106
|
function firstEmptyLeafPath(node, base = []) {
|
|
97
107
|
switch (node.kind) {
|
|
98
108
|
case "string":
|
|
@@ -463,6 +473,16 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
463
473
|
for (let i = 1; i < node.args.length; i++) row2.append(renderNode(node.args[i], [...path, "args", i], ctx));
|
|
464
474
|
return row2;
|
|
465
475
|
}
|
|
476
|
+
if (ctx.selfAdvanceRef && advancedRef(node, ctx.defaultScope) === normaliseRef(ctx.selfAdvanceRef, ctx.defaultScope)) {
|
|
477
|
+
const row2 = el("span", "exed-call exed-call-advance");
|
|
478
|
+
row2.append(pill(
|
|
479
|
+
"advance",
|
|
480
|
+
"advances",
|
|
481
|
+
(b) => callEditor(ctx, path, node, b),
|
|
482
|
+
{ issue, title: "advance one stage", aria: "advances one stage" }
|
|
483
|
+
));
|
|
484
|
+
return row2;
|
|
485
|
+
}
|
|
466
486
|
const row = el("span", "exed-call");
|
|
467
487
|
row.append(pill("func", node.name, (b) => callEditor(ctx, path, node, b), { issue }));
|
|
468
488
|
row.append(el("span", "exed-paren", ["("]));
|
|
@@ -1146,6 +1166,7 @@ function mountExpressionEditor(host, opts) {
|
|
|
1146
1166
|
},
|
|
1147
1167
|
...opts.requireNonEmpty ? { requireNonEmpty: true } : {},
|
|
1148
1168
|
...opts.valueEnumValues ? { valueEnumValues: opts.valueEnumValues } : {},
|
|
1169
|
+
...opts.selfAdvanceRef ? { selfAdvanceRef: opts.selfAdvanceRef } : {},
|
|
1149
1170
|
...opts.propertyActions ? { propertyActions: opts.propertyActions } : {},
|
|
1150
1171
|
...opts.pickNode ? { pickNode: opts.pickNode } : {},
|
|
1151
1172
|
...opts.nodeLabel ? { nodeLabel: opts.nodeLabel } : {}
|
|
@@ -1409,6 +1430,14 @@ function valueWizard(opts) {
|
|
|
1409
1430
|
}
|
|
1410
1431
|
|
|
1411
1432
|
// src/effects.ts
|
|
1433
|
+
function isSelfAdvance(eff, defaultScope, dialect) {
|
|
1434
|
+
if (eff.kind !== "set" || !eff.target) return false;
|
|
1435
|
+
try {
|
|
1436
|
+
return advancedRef(expr.parse(eff.value, dialect), defaultScope) === normaliseRef(eff.target, defaultScope);
|
|
1437
|
+
} catch {
|
|
1438
|
+
return false;
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1412
1441
|
var clone = (list) => list.map((e) => e.kind === "set" ? { ...e } : { ...e, args: [...e.args] });
|
|
1413
1442
|
var addSet = (list, target, value) => [...clone(list), { kind: "set", target, value }];
|
|
1414
1443
|
var addEmit = (list, event) => [...clone(list), { kind: "emit", event, args: [] }];
|
|
@@ -1505,7 +1534,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1505
1534
|
}), { container: opts.popoverContainer });
|
|
1506
1535
|
};
|
|
1507
1536
|
const targetType = (target) => opts.catalogue.find((e) => refOf(e, defaultScope) === target)?.type;
|
|
1508
|
-
const valueDisplay = (value, onChange, type) => {
|
|
1537
|
+
const valueDisplay = (value, onChange, type, selfAdvanceRef) => {
|
|
1509
1538
|
const sub = el("div", "exed-effect-value");
|
|
1510
1539
|
const addTerm = type === "number" ? "arithmetic" : type === "boolean" ? "boolean" : void 0;
|
|
1511
1540
|
inner.push(mountExpressionEditor(sub, {
|
|
@@ -1516,7 +1545,13 @@ function mountEffectsEditor(host, opts) {
|
|
|
1516
1545
|
scopeOrder: opts.scopeOrder,
|
|
1517
1546
|
functions: opts.functions,
|
|
1518
1547
|
mode: "flat",
|
|
1548
|
+
// Every editor here holds a VALUE (a set's value, an emit's argument), never a condition. Say
|
|
1549
|
+
// so, or emptying one falls back to the condition empty state and an outcome row reads
|
|
1550
|
+
// "always / + Add your first condition" - condition vocabulary, offering clauses where a value
|
|
1551
|
+
// belongs, and no way back to a value. `valueField` renders an editable empty literal instead.
|
|
1552
|
+
valueField: true,
|
|
1519
1553
|
...addTerm ? { addTerm } : {},
|
|
1554
|
+
...selfAdvanceRef ? { selfAdvanceRef } : {},
|
|
1520
1555
|
...opts.popoverContainer ? { popoverContainer: opts.popoverContainer } : {},
|
|
1521
1556
|
text: textMode,
|
|
1522
1557
|
onChange
|
|
@@ -1567,11 +1602,18 @@ function mountEffectsEditor(host, opts) {
|
|
|
1567
1602
|
commit(updateAt(effects, i, { target: refOf(entry, defaultScope), value: initialValueFor(entry, defaultScope).src }));
|
|
1568
1603
|
});
|
|
1569
1604
|
}, "change the target property");
|
|
1570
|
-
|
|
1605
|
+
const advances = isSelfAdvance(eff, defaultScope, opts.dialect);
|
|
1606
|
+
row.append(targetBtn);
|
|
1607
|
+
if (!advances) row.append(el("span", "exed-effect-eq", ["="]));
|
|
1571
1608
|
row.append(valueDisplay(eff.value, (src) => {
|
|
1572
|
-
|
|
1609
|
+
const next = updateAt(effects, i, { value: src });
|
|
1610
|
+
if (isSelfAdvance(next[i], defaultScope, opts.dialect) !== advances) {
|
|
1611
|
+
commit(next);
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
effects = next;
|
|
1573
1615
|
opts.onChange(effects);
|
|
1574
|
-
}, targetType(eff.target)));
|
|
1616
|
+
}, targetType(eff.target), advances ? eff.target : void 0));
|
|
1575
1617
|
row.append(rowActions2(i));
|
|
1576
1618
|
return row;
|
|
1577
1619
|
}
|
|
@@ -1685,7 +1727,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1685
1727
|
}
|
|
1686
1728
|
|
|
1687
1729
|
// src/preview.ts
|
|
1688
|
-
function frozenCtx(src, o) {
|
|
1730
|
+
function frozenCtx(src, o, selfAdvanceRef) {
|
|
1689
1731
|
const v = validateSource(src, o.schema, o.dialect);
|
|
1690
1732
|
const ctx = {
|
|
1691
1733
|
schema: o.schema,
|
|
@@ -1704,6 +1746,7 @@ function frozenCtx(src, o) {
|
|
|
1704
1746
|
pickNode: () => {
|
|
1705
1747
|
},
|
|
1706
1748
|
// enables labelled node pills; never fires (preview is read-only)
|
|
1749
|
+
...selfAdvanceRef ? { selfAdvanceRef } : {},
|
|
1707
1750
|
...o.nodeLabel ? { nodeLabel: o.nodeLabel } : {},
|
|
1708
1751
|
...o.propertyActions ? {
|
|
1709
1752
|
propertyActions: o.propertyActions,
|
|
@@ -1714,8 +1757,8 @@ function frozenCtx(src, o) {
|
|
|
1714
1757
|
};
|
|
1715
1758
|
return { ctx, ast: v.ast };
|
|
1716
1759
|
}
|
|
1717
|
-
function exprPills(src, o) {
|
|
1718
|
-
const { ctx, ast } = frozenCtx(src, o);
|
|
1760
|
+
function exprPills(src, o, selfAdvanceRef) {
|
|
1761
|
+
const { ctx, ast } = frozenCtx(src, o, selfAdvanceRef);
|
|
1719
1762
|
return ast ? renderNode(ast, [], ctx) : el("span", "exed-preview-raw", [src]);
|
|
1720
1763
|
}
|
|
1721
1764
|
function renderConditionPreview(src, o) {
|
|
@@ -1727,9 +1770,10 @@ function renderEffectsPreview(effects, o) {
|
|
|
1727
1770
|
for (const eff of effects) {
|
|
1728
1771
|
const row = el("div", "exed-preview-eff");
|
|
1729
1772
|
if (eff.kind === "set") {
|
|
1773
|
+
const advances = isSelfAdvance(eff, o.dialect.defaultScope, o.dialect);
|
|
1730
1774
|
row.append(el("span", "exed-pill exed-pill-prop", [eff.target || "(property)"]));
|
|
1731
|
-
row.append(el("span", "exed-effect-eq", ["="]));
|
|
1732
|
-
row.append(exprPills(eff.value, o));
|
|
1775
|
+
if (!advances) row.append(el("span", "exed-effect-eq", ["="]));
|
|
1776
|
+
row.append(exprPills(eff.value, o, advances ? eff.target : void 0));
|
|
1733
1777
|
} else {
|
|
1734
1778
|
row.append(el("span", "exed-effect-kw", ["emit"]));
|
|
1735
1779
|
row.append(el("span", "exed-pill exed-pill-event", [eff.event ? `"${eff.event}"` : "(name)"]));
|
|
@@ -1756,6 +1800,7 @@ exports.addArg = addArg;
|
|
|
1756
1800
|
exports.addChildToContainer = addChildToContainer;
|
|
1757
1801
|
exports.addEmit = addEmit;
|
|
1758
1802
|
exports.addSet = addSet;
|
|
1803
|
+
exports.advancedRef = advancedRef;
|
|
1759
1804
|
exports.astToTree = astToTree;
|
|
1760
1805
|
exports.binary = binary;
|
|
1761
1806
|
exports.boolLit = boolLit;
|
|
@@ -1786,6 +1831,7 @@ exports.mountExpressionEditor = mountExpressionEditor;
|
|
|
1786
1831
|
exports.moveAt = moveAt;
|
|
1787
1832
|
exports.moveChildInContainer = moveChildInContainer;
|
|
1788
1833
|
exports.needsParens = needsParens;
|
|
1834
|
+
exports.normaliseRef = normaliseRef;
|
|
1789
1835
|
exports.notNode = notNode;
|
|
1790
1836
|
exports.numLit = numLit;
|
|
1791
1837
|
exports.opSwapGroup = opSwapGroup;
|