@wildwinter/expr-editor 0.15.3 → 0.16.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/README.md CHANGED
@@ -35,6 +35,12 @@ Notable options beyond the basics:
35
35
  multi-step flow (e.g. tag → operator → threshold) with no editor changes.
36
36
  Templates without a wizard insert-then-refine: the editor auto-opens the
37
37
  first unfilled slot of the inserted clause.
38
+ - `otherEngineScopes`: scopes another engine owns (a product family's shared
39
+ vocabulary, such as `patter` in a Storylets card). Their names never appear in
40
+ the host's catalogue, because the other engine checks them, so a reference into
41
+ one renders as an ordinary property pill with a tip saying whose it is, instead
42
+ of an unknown property. Accepted by the expression editor, the effects editor,
43
+ and the previews.
38
44
  - **Qualities** (the `quality` property type) need nothing from the host beyond a
39
45
  catalogue entry carrying `stages` — the ladder, in order. The editor then offers
40
46
  the property in a comparison clause, gives it the **ordering** operators (a
package/dist/index.cjs CHANGED
@@ -309,6 +309,20 @@ function searchCatalogue(entries, query, defaultScope) {
309
309
  if (!q) return [...entries];
310
310
  return entries.filter((e) => displayName(e, defaultScope).toLowerCase().includes(q) || (e.purpose ?? "").toLowerCase().includes(q));
311
311
  }
312
+ function otherEngineTip(label) {
313
+ return `${label} belongs to another engine, which checks it`;
314
+ }
315
+ function propertyPillNote(entry, scope, label, otherEngineScopes) {
316
+ if (entry) {
317
+ const title = propertyTip(entry);
318
+ return title ? { title } : {};
319
+ }
320
+ if (otherEngineScopes?.includes(scope)) return { title: otherEngineTip(label) };
321
+ return { issue: `Unknown property ${label}` };
322
+ }
323
+ function scopeOfRef(ref) {
324
+ return /^@([^.\s]+)\./.exec(ref)?.[1];
325
+ }
312
326
  function groupByScope(entries, scopeOrder = []) {
313
327
  const byScope = /* @__PURE__ */ new Map();
314
328
  for (const e of entries) {
@@ -482,11 +496,12 @@ function renderNode(node, path, ctx, parentOp, side) {
482
496
  case "scopedvar": {
483
497
  const entry = lookup(ctx.catalogue, node.scope, node.name);
484
498
  const label = displayName({ scope: node.scope, name: node.name }, ctx.defaultScope);
499
+ const note = propertyPillNote(entry, node.scope, label, ctx.otherEngineScopes);
485
500
  const varPill = pill(
486
501
  "var",
487
502
  label,
488
503
  (b) => variableEditor(ctx, path, node, b),
489
- { issue: issue ?? (entry ? void 0 : `Unknown property ${label}`), title: propertyTip(entry) }
504
+ { issue: issue ?? note.issue, title: note.title }
490
505
  );
491
506
  attachPropertyMenu(ctx, node, varPill);
492
507
  return varPill;
@@ -1167,6 +1182,7 @@ function mountExpressionEditor(host, opts) {
1167
1182
  catalogue: opts.catalogue,
1168
1183
  scopeOrder: opts.scopeOrder ?? [],
1169
1184
  functions: opts.functions ?? [],
1185
+ ...opts.otherEngineScopes ? { otherEngineScopes: opts.otherEngineScopes } : {},
1170
1186
  byPath: v.byPath,
1171
1187
  getAst: () => ast,
1172
1188
  apply: (next) => emit(toSrc(next)),
@@ -1608,6 +1624,7 @@ function mountEffectsEditor(host, opts) {
1608
1624
  scopeOrder: opts.scopeOrder,
1609
1625
  functions: opts.functions,
1610
1626
  mode: "flat",
1627
+ ...opts.otherEngineScopes ? { otherEngineScopes: opts.otherEngineScopes } : {},
1611
1628
  // Every editor here holds a VALUE (a set's value, an emit's argument), never a condition. Say
1612
1629
  // so, or emptying one falls back to the condition empty state and an outcome row reads
1613
1630
  // "always / + Add your first condition" - condition vocabulary, offering clauses where a value
@@ -1667,7 +1684,8 @@ function mountEffectsEditor(host, opts) {
1667
1684
  });
1668
1685
  }, "change the target property");
1669
1686
  const targetEntry = entryForTarget(opts.catalogue, eff.target, defaultScope);
1670
- const tip = propertyTip(targetEntry);
1687
+ const targetScope = targetEntry ? void 0 : scopeOfRef(eff.target);
1688
+ const tip = targetScope !== void 0 && opts.otherEngineScopes?.includes(targetScope) ? otherEngineTip(eff.target) : propertyTip(targetEntry);
1671
1689
  if (tip) targetBtn.title = tip;
1672
1690
  if (targetEntry && opts.propertyActions) {
1673
1691
  const actions = opts.propertyActions({ scope: targetEntry.scope, name: targetEntry.name });
@@ -1811,6 +1829,7 @@ function frozenCtx(src, o, selfAdvanceRef) {
1811
1829
  catalogue: o.catalogue,
1812
1830
  scopeOrder: o.scopeOrder ?? [],
1813
1831
  functions: [],
1832
+ ...o.otherEngineScopes ? { otherEngineScopes: o.otherEngineScopes } : {},
1814
1833
  compact: true,
1815
1834
  byPath: v.byPath,
1816
1835
  getAst: () => v.ast,
@@ -1843,7 +1862,11 @@ function renderConditionPreview(src, o) {
1843
1862
  function targetPill(ref, o) {
1844
1863
  const pill2 = el("span", "exed-pill exed-pill-prop", [ref || "(property)"]);
1845
1864
  const entry = o.catalogue.find((e) => refOf(e, o.dialect.defaultScope) === ref);
1846
- if (!entry) return pill2;
1865
+ if (!entry) {
1866
+ const scope = scopeOfRef(ref);
1867
+ if (scope !== void 0 && o.otherEngineScopes?.includes(scope)) pill2.title = otherEngineTip(ref);
1868
+ return pill2;
1869
+ }
1847
1870
  const tip = propertyTip(entry);
1848
1871
  if (tip) pill2.title = tip;
1849
1872
  const actions = o.propertyActions?.({ scope: entry.scope, name: entry.name }) ?? [];
@@ -1924,8 +1947,10 @@ exports.normaliseRef = normaliseRef;
1924
1947
  exports.notNode = notNode;
1925
1948
  exports.numLit = numLit;
1926
1949
  exports.opSwapGroup = opSwapGroup;
1950
+ exports.otherEngineTip = otherEngineTip;
1927
1951
  exports.pathKey = pathKey;
1928
1952
  exports.placeholderForOp = placeholderForOp;
1953
+ exports.propertyPillNote = propertyPillNote;
1929
1954
  exports.propertyTip = propertyTip;
1930
1955
  exports.redirectDeleteForPlaceholderSibling = redirectDeleteForPlaceholderSibling;
1931
1956
  exports.refOf = refOf;
@@ -1934,6 +1959,7 @@ exports.removeAt = removeAt;
1934
1959
  exports.renderConditionPreview = renderConditionPreview;
1935
1960
  exports.renderEffectsPreview = renderEffectsPreview;
1936
1961
  exports.rhsTypesFor = rhsTypesFor;
1962
+ exports.scopeOfRef = scopeOfRef;
1937
1963
  exports.scopedVar = scopedVar;
1938
1964
  exports.searchCatalogue = searchCatalogue;
1939
1965
  exports.seedValueSrc = seedValueSrc;