@wildwinter/expr-editor 0.12.2 → 0.13.0
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 +75 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +74 -39
- package/dist/index.js.map +1 -1
- package/dist/styles.css +18 -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":
|
|
@@ -221,6 +231,22 @@ var BINARY_LABEL = {
|
|
|
221
231
|
"/": "\xF7"
|
|
222
232
|
};
|
|
223
233
|
var UNARY_LABEL = { not: "NOT", neg: "\u2212" };
|
|
234
|
+
var OP_WORD = {
|
|
235
|
+
"==": "equals",
|
|
236
|
+
"!=": "not equal to",
|
|
237
|
+
">": "greater than",
|
|
238
|
+
">=": "at least",
|
|
239
|
+
"<": "less than",
|
|
240
|
+
"<=": "at most",
|
|
241
|
+
and: "and",
|
|
242
|
+
or: "or",
|
|
243
|
+
"+": "plus",
|
|
244
|
+
"-": "minus",
|
|
245
|
+
"*": "times",
|
|
246
|
+
"/": "divided by",
|
|
247
|
+
not: "not",
|
|
248
|
+
neg: "negative"
|
|
249
|
+
};
|
|
224
250
|
var COMPARISON_OPS = ["==", "!=", ">", ">=", "<", "<="];
|
|
225
251
|
var ARITHMETIC_OPS = ["+", "-", "*", "/"];
|
|
226
252
|
var COMPARABLE_TYPES = ["boolean", "number", "string", "enum", "quality"];
|
|
@@ -406,20 +432,6 @@ function pill(kind, label, onClick, opts = {}) {
|
|
|
406
432
|
if (opts.path) b.dataset["exedPath"] = opts.path.join("/");
|
|
407
433
|
return b;
|
|
408
434
|
}
|
|
409
|
-
var OP_ARIA = {
|
|
410
|
-
"==": "equals",
|
|
411
|
-
"!=": "not equal to",
|
|
412
|
-
">": "greater than",
|
|
413
|
-
">=": "at least",
|
|
414
|
-
"<": "less than",
|
|
415
|
-
"<=": "at most",
|
|
416
|
-
"and": "and",
|
|
417
|
-
"or": "or",
|
|
418
|
-
"+": "plus",
|
|
419
|
-
"-": "minus",
|
|
420
|
-
"*": "times",
|
|
421
|
-
"/": "divided by"
|
|
422
|
-
};
|
|
423
435
|
var issueText = (ctx, path) => {
|
|
424
436
|
const list = issuesAt(ctx.byPath, path);
|
|
425
437
|
return list.length ? list.map((i) => i.message).join("; ") : void 0;
|
|
@@ -461,6 +473,16 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
461
473
|
for (let i = 1; i < node.args.length; i++) row2.append(renderNode(node.args[i], [...path, "args", i], ctx));
|
|
462
474
|
return row2;
|
|
463
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
|
+
}
|
|
464
486
|
const row = el("span", "exed-call");
|
|
465
487
|
row.append(pill("func", node.name, (b) => callEditor(ctx, path, node, b), { issue }));
|
|
466
488
|
row.append(el("span", "exed-paren", ["("]));
|
|
@@ -473,7 +495,7 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
473
495
|
}
|
|
474
496
|
case "unary": {
|
|
475
497
|
const row = el("span", "exed-unary");
|
|
476
|
-
row.append(pill("op", UNARY_LABEL[node.op], () => ctx.apply(deleteOrUnwrapNot(ctx, path, node)), { title: "remove", aria: `${
|
|
498
|
+
row.append(pill("op", UNARY_LABEL[node.op], () => ctx.apply(deleteOrUnwrapNot(ctx, path, node)), { title: "remove", aria: `${OP_WORD[node.op]} (click to remove)` }));
|
|
477
499
|
row.append(renderNode(node.operand, [...path, "operand"], ctx));
|
|
478
500
|
return row;
|
|
479
501
|
}
|
|
@@ -485,7 +507,7 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
485
507
|
const swap = opSwapGroup(node.op);
|
|
486
508
|
const opPill = pill("op", BINARY_LABEL[node.op], (b) => {
|
|
487
509
|
if (swap) operatorEditor(ctx, path, node.op, swap, b);
|
|
488
|
-
}, { title: swap ? "swap operator" : void 0, aria:
|
|
510
|
+
}, { title: swap ? "swap operator" : void 0, aria: OP_WORD[node.op] });
|
|
489
511
|
if (!swap) opPill.classList.add("exed-op-structural");
|
|
490
512
|
row.append(opPill);
|
|
491
513
|
row.append(renderNode(node.right, [...path, "right"], ctx, node.op, "right"));
|
|
@@ -596,12 +618,14 @@ function operatorEditor(ctx, path, current, group, anchor) {
|
|
|
596
618
|
const wrap = el("div", "exed-menu");
|
|
597
619
|
wrap.append(el("div", "exed-menu-head", ["Operator"]));
|
|
598
620
|
for (const op of group) {
|
|
599
|
-
|
|
621
|
+
const row = button(`exed-opt exed-opt-op${op === current ? " sel" : ""}`, "", () => {
|
|
600
622
|
const node = ctx.getAst();
|
|
601
623
|
const cur = setNodeAt(node, path, { ...getBinary(ctx, path), op });
|
|
602
624
|
ctx.apply(cur);
|
|
603
625
|
close();
|
|
604
|
-
})
|
|
626
|
+
});
|
|
627
|
+
row.append(el("span", "exed-opt-name", [BINARY_LABEL[op]]), el("span", "exed-opt-purpose", [OP_WORD[op]]));
|
|
628
|
+
wrap.append(row);
|
|
605
629
|
}
|
|
606
630
|
return wrap;
|
|
607
631
|
});
|
|
@@ -717,17 +741,9 @@ function propertyPicker(ctx, opts) {
|
|
|
717
741
|
}
|
|
718
742
|
|
|
719
743
|
// src/clausewizard.ts
|
|
720
|
-
var OP_WORD = {
|
|
721
|
-
"==": "equals",
|
|
722
|
-
"!=": "not equal to",
|
|
723
|
-
">": "greater than",
|
|
724
|
-
">=": "at least",
|
|
725
|
-
"<": "less than",
|
|
726
|
-
"<=": "at most"
|
|
727
|
-
};
|
|
728
744
|
var opButton = (o, onClick) => {
|
|
729
|
-
const b = button("exed-opt", "", onClick);
|
|
730
|
-
b.append(el("span", "exed-opt-name", [BINARY_LABEL[o]]), el("span", "exed-opt-purpose", [OP_WORD[o]
|
|
745
|
+
const b = button("exed-opt exed-opt-op", "", onClick);
|
|
746
|
+
b.append(el("span", "exed-opt-name", [BINARY_LABEL[o]]), el("span", "exed-opt-purpose", [OP_WORD[o]]));
|
|
731
747
|
return b;
|
|
732
748
|
};
|
|
733
749
|
function header(host, title, back, cancel) {
|
|
@@ -1150,6 +1166,7 @@ function mountExpressionEditor(host, opts) {
|
|
|
1150
1166
|
},
|
|
1151
1167
|
...opts.requireNonEmpty ? { requireNonEmpty: true } : {},
|
|
1152
1168
|
...opts.valueEnumValues ? { valueEnumValues: opts.valueEnumValues } : {},
|
|
1169
|
+
...opts.selfAdvanceRef ? { selfAdvanceRef: opts.selfAdvanceRef } : {},
|
|
1153
1170
|
...opts.propertyActions ? { propertyActions: opts.propertyActions } : {},
|
|
1154
1171
|
...opts.pickNode ? { pickNode: opts.pickNode } : {},
|
|
1155
1172
|
...opts.nodeLabel ? { nodeLabel: opts.nodeLabel } : {}
|
|
@@ -1413,6 +1430,14 @@ function valueWizard(opts) {
|
|
|
1413
1430
|
}
|
|
1414
1431
|
|
|
1415
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
|
+
}
|
|
1416
1441
|
var clone = (list) => list.map((e) => e.kind === "set" ? { ...e } : { ...e, args: [...e.args] });
|
|
1417
1442
|
var addSet = (list, target, value) => [...clone(list), { kind: "set", target, value }];
|
|
1418
1443
|
var addEmit = (list, event) => [...clone(list), { kind: "emit", event, args: [] }];
|
|
@@ -1509,7 +1534,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1509
1534
|
}), { container: opts.popoverContainer });
|
|
1510
1535
|
};
|
|
1511
1536
|
const targetType = (target) => opts.catalogue.find((e) => refOf(e, defaultScope) === target)?.type;
|
|
1512
|
-
const valueDisplay = (value, onChange, type) => {
|
|
1537
|
+
const valueDisplay = (value, onChange, type, selfAdvanceRef) => {
|
|
1513
1538
|
const sub = el("div", "exed-effect-value");
|
|
1514
1539
|
const addTerm = type === "number" ? "arithmetic" : type === "boolean" ? "boolean" : void 0;
|
|
1515
1540
|
inner.push(mountExpressionEditor(sub, {
|
|
@@ -1521,6 +1546,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1521
1546
|
functions: opts.functions,
|
|
1522
1547
|
mode: "flat",
|
|
1523
1548
|
...addTerm ? { addTerm } : {},
|
|
1549
|
+
...selfAdvanceRef ? { selfAdvanceRef } : {},
|
|
1524
1550
|
...opts.popoverContainer ? { popoverContainer: opts.popoverContainer } : {},
|
|
1525
1551
|
text: textMode,
|
|
1526
1552
|
onChange
|
|
@@ -1571,11 +1597,18 @@ function mountEffectsEditor(host, opts) {
|
|
|
1571
1597
|
commit(updateAt(effects, i, { target: refOf(entry, defaultScope), value: initialValueFor(entry, defaultScope).src }));
|
|
1572
1598
|
});
|
|
1573
1599
|
}, "change the target property");
|
|
1574
|
-
|
|
1600
|
+
const advances = isSelfAdvance(eff, defaultScope, opts.dialect);
|
|
1601
|
+
row.append(targetBtn);
|
|
1602
|
+
if (!advances) row.append(el("span", "exed-effect-eq", ["="]));
|
|
1575
1603
|
row.append(valueDisplay(eff.value, (src) => {
|
|
1576
|
-
|
|
1604
|
+
const next = updateAt(effects, i, { value: src });
|
|
1605
|
+
if (isSelfAdvance(next[i], defaultScope, opts.dialect) !== advances) {
|
|
1606
|
+
commit(next);
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
effects = next;
|
|
1577
1610
|
opts.onChange(effects);
|
|
1578
|
-
}, targetType(eff.target)));
|
|
1611
|
+
}, targetType(eff.target), advances ? eff.target : void 0));
|
|
1579
1612
|
row.append(rowActions2(i));
|
|
1580
1613
|
return row;
|
|
1581
1614
|
}
|
|
@@ -1689,7 +1722,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1689
1722
|
}
|
|
1690
1723
|
|
|
1691
1724
|
// src/preview.ts
|
|
1692
|
-
function frozenCtx(src, o) {
|
|
1725
|
+
function frozenCtx(src, o, selfAdvanceRef) {
|
|
1693
1726
|
const v = validateSource(src, o.schema, o.dialect);
|
|
1694
1727
|
const ctx = {
|
|
1695
1728
|
schema: o.schema,
|
|
@@ -1708,6 +1741,7 @@ function frozenCtx(src, o) {
|
|
|
1708
1741
|
pickNode: () => {
|
|
1709
1742
|
},
|
|
1710
1743
|
// enables labelled node pills; never fires (preview is read-only)
|
|
1744
|
+
...selfAdvanceRef ? { selfAdvanceRef } : {},
|
|
1711
1745
|
...o.nodeLabel ? { nodeLabel: o.nodeLabel } : {},
|
|
1712
1746
|
...o.propertyActions ? {
|
|
1713
1747
|
propertyActions: o.propertyActions,
|
|
@@ -1718,8 +1752,8 @@ function frozenCtx(src, o) {
|
|
|
1718
1752
|
};
|
|
1719
1753
|
return { ctx, ast: v.ast };
|
|
1720
1754
|
}
|
|
1721
|
-
function exprPills(src, o) {
|
|
1722
|
-
const { ctx, ast } = frozenCtx(src, o);
|
|
1755
|
+
function exprPills(src, o, selfAdvanceRef) {
|
|
1756
|
+
const { ctx, ast } = frozenCtx(src, o, selfAdvanceRef);
|
|
1723
1757
|
return ast ? renderNode(ast, [], ctx) : el("span", "exed-preview-raw", [src]);
|
|
1724
1758
|
}
|
|
1725
1759
|
function renderConditionPreview(src, o) {
|
|
@@ -1731,9 +1765,10 @@ function renderEffectsPreview(effects, o) {
|
|
|
1731
1765
|
for (const eff of effects) {
|
|
1732
1766
|
const row = el("div", "exed-preview-eff");
|
|
1733
1767
|
if (eff.kind === "set") {
|
|
1768
|
+
const advances = isSelfAdvance(eff, o.dialect.defaultScope, o.dialect);
|
|
1734
1769
|
row.append(el("span", "exed-pill exed-pill-prop", [eff.target || "(property)"]));
|
|
1735
|
-
row.append(el("span", "exed-effect-eq", ["="]));
|
|
1736
|
-
row.append(exprPills(eff.value, o));
|
|
1770
|
+
if (!advances) row.append(el("span", "exed-effect-eq", ["="]));
|
|
1771
|
+
row.append(exprPills(eff.value, o, advances ? eff.target : void 0));
|
|
1737
1772
|
} else {
|
|
1738
1773
|
row.append(el("span", "exed-effect-kw", ["emit"]));
|
|
1739
1774
|
row.append(el("span", "exed-pill exed-pill-event", [eff.event ? `"${eff.event}"` : "(name)"]));
|
|
@@ -1754,11 +1789,13 @@ exports.BINARY_LABEL = BINARY_LABEL;
|
|
|
1754
1789
|
exports.COMPARABLE_TYPES = COMPARABLE_TYPES;
|
|
1755
1790
|
exports.COMPARISON_OPS = COMPARISON_OPS;
|
|
1756
1791
|
exports.EQUALITY_OPS = EQUALITY_OPS;
|
|
1792
|
+
exports.OP_WORD = OP_WORD;
|
|
1757
1793
|
exports.UNARY_LABEL = UNARY_LABEL;
|
|
1758
1794
|
exports.addArg = addArg;
|
|
1759
1795
|
exports.addChildToContainer = addChildToContainer;
|
|
1760
1796
|
exports.addEmit = addEmit;
|
|
1761
1797
|
exports.addSet = addSet;
|
|
1798
|
+
exports.advancedRef = advancedRef;
|
|
1762
1799
|
exports.astToTree = astToTree;
|
|
1763
1800
|
exports.binary = binary;
|
|
1764
1801
|
exports.boolLit = boolLit;
|
|
@@ -1789,6 +1826,7 @@ exports.mountExpressionEditor = mountExpressionEditor;
|
|
|
1789
1826
|
exports.moveAt = moveAt;
|
|
1790
1827
|
exports.moveChildInContainer = moveChildInContainer;
|
|
1791
1828
|
exports.needsParens = needsParens;
|
|
1829
|
+
exports.normaliseRef = normaliseRef;
|
|
1792
1830
|
exports.notNode = notNode;
|
|
1793
1831
|
exports.numLit = numLit;
|
|
1794
1832
|
exports.opSwapGroup = opSwapGroup;
|