@player-ui/player 0.4.0-next.0 → 0.4.0-next.10

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.
Files changed (42) hide show
  1. package/dist/index.cjs.js +730 -362
  2. package/dist/index.d.ts +220 -81
  3. package/dist/index.esm.js +726 -364
  4. package/dist/player.dev.js +12311 -0
  5. package/dist/player.prod.js +2 -0
  6. package/package.json +14 -5
  7. package/src/binding/binding.ts +8 -0
  8. package/src/binding/index.ts +1 -1
  9. package/src/controllers/constants/index.ts +9 -5
  10. package/src/controllers/data.ts +49 -54
  11. package/src/controllers/flow/controller.ts +16 -12
  12. package/src/controllers/flow/flow.ts +6 -1
  13. package/src/controllers/validation/binding-tracker.ts +42 -19
  14. package/src/controllers/validation/controller.ts +265 -85
  15. package/src/controllers/view/asset-transform.ts +4 -1
  16. package/src/controllers/view/controller.ts +19 -2
  17. package/src/data/dependency-tracker.ts +14 -0
  18. package/src/data/local-model.ts +25 -1
  19. package/src/data/model.ts +55 -8
  20. package/src/data/noop-model.ts +2 -0
  21. package/src/expressions/evaluator-functions.ts +24 -2
  22. package/src/expressions/evaluator.ts +37 -33
  23. package/src/expressions/index.ts +1 -0
  24. package/src/expressions/parser.ts +53 -27
  25. package/src/expressions/types.ts +23 -5
  26. package/src/expressions/utils.ts +19 -0
  27. package/src/player.ts +44 -48
  28. package/src/plugins/default-exp-plugin.ts +57 -0
  29. package/src/plugins/flow-exp-plugin.ts +2 -2
  30. package/src/schema/schema.ts +28 -9
  31. package/src/string-resolver/index.ts +25 -9
  32. package/src/types.ts +1 -4
  33. package/src/validator/binding-map-splice.ts +59 -0
  34. package/src/validator/index.ts +1 -0
  35. package/src/validator/types.ts +11 -3
  36. package/src/validator/validation-middleware.ts +38 -4
  37. package/src/view/parser/index.ts +51 -3
  38. package/src/view/plugins/applicability.ts +1 -1
  39. package/src/view/plugins/string-resolver.ts +8 -4
  40. package/src/view/plugins/template-plugin.ts +1 -6
  41. package/src/view/resolver/index.ts +119 -54
  42. package/src/view/resolver/types.ts +48 -7
package/dist/index.esm.js CHANGED
@@ -5,7 +5,7 @@ import flatten$1 from 'arr-flatten';
5
5
  import P from 'parsimmon';
6
6
  import { Grammars } from 'ebnf';
7
7
  import get from 'dlv';
8
- import { setIn, addLast, set, omit, removeAt } from 'timm';
8
+ import { setIn, removeAt, omit, clone, addLast, set } from 'timm';
9
9
  import { dequal } from 'dequal';
10
10
  import defer from 'p-defer';
11
11
  import queueMicrotask from 'queue-microtask';
@@ -542,7 +542,7 @@ class BindingParser {
542
542
  updates = __spreadValues$d(__spreadValues$d({}, updates), normalized.updates);
543
543
  }
544
544
  const updateKeys = Object.keys(updates);
545
- if (updateKeys.length > 0) {
545
+ if (!options.readOnly && updateKeys.length > 0) {
546
546
  const updateTransaction = updateKeys.map((updatedBinding) => [
547
547
  this.parse(updatedBinding),
548
548
  updates[updatedBinding]
@@ -638,6 +638,10 @@ class DependencyMiddleware extends DependencyTracker {
638
638
  this.addReadDep(binding);
639
639
  return next == null ? void 0 : next.get(binding, options);
640
640
  }
641
+ delete(binding, options, next) {
642
+ this.addWriteDep(binding);
643
+ return next == null ? void 0 : next.delete(binding, options);
644
+ }
641
645
  }
642
646
  class DependencyModel extends DependencyTracker {
643
647
  constructor(rootModel) {
@@ -654,6 +658,10 @@ class DependencyModel extends DependencyTracker {
654
658
  this.addReadDep(binding);
655
659
  return this.rootModel.get(binding, options);
656
660
  }
661
+ delete(binding, options) {
662
+ this.addWriteDep(binding);
663
+ return this.rootModel.delete(binding, options);
664
+ }
657
665
  }
658
666
 
659
667
  class NOOPDataModel {
@@ -663,15 +671,18 @@ class NOOPDataModel {
663
671
  set() {
664
672
  return [];
665
673
  }
674
+ delete() {
675
+ }
666
676
  }
667
677
  const NOOP_MODEL = new NOOPDataModel();
668
678
 
669
679
  const ROOT_BINDING = new BindingInstance([]);
670
680
  function withParser(model, parseBinding) {
671
- function maybeParse(binding) {
681
+ function maybeParse(binding, readOnly) {
672
682
  const parsed = isBinding(binding) ? binding : parseBinding(binding, {
673
683
  get: model.get,
674
- set: model.set
684
+ set: model.set,
685
+ readOnly
675
686
  });
676
687
  if (!parsed) {
677
688
  throw new Error("Unable to parse binding");
@@ -680,10 +691,13 @@ function withParser(model, parseBinding) {
680
691
  }
681
692
  return {
682
693
  get(binding, options) {
683
- return model.get(maybeParse(binding), options);
694
+ return model.get(maybeParse(binding, true), options);
684
695
  },
685
696
  set(transaction, options) {
686
- return model.set(transaction.map(([key, val]) => [maybeParse(key), val]), options);
697
+ return model.set(transaction.map(([key, val]) => [maybeParse(key, false), val]), options);
698
+ },
699
+ delete(binding, options) {
700
+ return model.delete(maybeParse(binding, false), options);
687
701
  }
688
702
  };
689
703
  }
@@ -692,8 +706,27 @@ function toModel(middleware, defaultOptions, next) {
692
706
  return middleware;
693
707
  }
694
708
  return {
695
- get: (binding, options) => middleware.get(binding, options != null ? options : defaultOptions, next),
696
- set: (transaction, options) => middleware.set(transaction, options != null ? options : defaultOptions, next)
709
+ get: (binding, options) => {
710
+ const resolvedOptions = options != null ? options : defaultOptions;
711
+ if (middleware.get) {
712
+ return middleware.get(binding, resolvedOptions, next);
713
+ }
714
+ return next == null ? void 0 : next.get(binding, resolvedOptions);
715
+ },
716
+ set: (transaction, options) => {
717
+ const resolvedOptions = options != null ? options : defaultOptions;
718
+ if (middleware.set) {
719
+ return middleware.set(transaction, resolvedOptions, next);
720
+ }
721
+ return next == null ? void 0 : next.set(transaction, resolvedOptions);
722
+ },
723
+ delete: (binding, options) => {
724
+ const resolvedOptions = options != null ? options : defaultOptions;
725
+ if (middleware.delete) {
726
+ return middleware.delete(binding, resolvedOptions, next);
727
+ }
728
+ return next == null ? void 0 : next.delete(binding, resolvedOptions);
729
+ }
697
730
  };
698
731
  }
699
732
  function constructModelForPipeline(pipeline) {
@@ -701,7 +734,7 @@ function constructModelForPipeline(pipeline) {
701
734
  return NOOP_MODEL;
702
735
  }
703
736
  if (pipeline.length === 1) {
704
- return pipeline[0];
737
+ return toModel(pipeline[0]);
705
738
  }
706
739
  function createModelWithOptions(options) {
707
740
  var _a;
@@ -716,6 +749,10 @@ function constructModelForPipeline(pipeline) {
716
749
  set: (transaction, options) => {
717
750
  var _a;
718
751
  return (_a = createModelWithOptions(options)) == null ? void 0 : _a.set(transaction, options);
752
+ },
753
+ delete: (binding, options) => {
754
+ var _a;
755
+ return (_a = createModelWithOptions(options)) == null ? void 0 : _a.delete(binding, options);
719
756
  }
720
757
  };
721
758
  }
@@ -752,6 +789,9 @@ class PipelinedDataModel {
752
789
  get(binding, options) {
753
790
  return this.effectiveDataModel.get(binding, options);
754
791
  }
792
+ delete(binding, options) {
793
+ return this.effectiveDataModel.delete(binding, options);
794
+ }
755
795
  }
756
796
 
757
797
  class LocalModel {
@@ -778,11 +818,24 @@ class LocalModel {
778
818
  });
779
819
  return effectiveOperations;
780
820
  }
821
+ delete(binding) {
822
+ const parentBinding = binding.parent();
823
+ if (parentBinding) {
824
+ const parentValue = this.get(parentBinding);
825
+ if (parentValue !== void 0) {
826
+ if (Array.isArray(parentValue)) {
827
+ this.model = setIn(this.model, parentBinding.asArray(), removeAt(parentValue, binding.key()));
828
+ } else {
829
+ this.model = setIn(this.model, parentBinding.asArray(), omit(parentValue, binding.key()));
830
+ }
831
+ }
832
+ }
833
+ }
781
834
  }
782
835
 
783
836
  const ExpNodeOpaqueIdentifier = Symbol("Expression Node ID");
784
837
  function isExpressionNode(x) {
785
- return typeof x === "object" && x.__id === ExpNodeOpaqueIdentifier;
838
+ return typeof x === "object" && x !== null && !Array.isArray(x) && x.__id === ExpNodeOpaqueIdentifier;
786
839
  }
787
840
 
788
841
  const PERIOD_CODE = 46;
@@ -896,7 +949,9 @@ function isIdentifierPart(ch) {
896
949
  function isModelRefStart(ch0, ch1) {
897
950
  return ch0 === OCURL_CODE && ch1 === OCURL_CODE;
898
951
  }
899
- function parseExpression(expr) {
952
+ function parseExpression(expr, options) {
953
+ var _a;
954
+ const strictMode = (_a = options == null ? void 0 : options.strict) != null ? _a : true;
900
955
  const charAtFunc = expr.charAt;
901
956
  const charCodeAtFunc = expr.charCodeAt;
902
957
  const { length } = expr;
@@ -1290,6 +1345,9 @@ function parseExpression(expr) {
1290
1345
  }
1291
1346
  args.push(node);
1292
1347
  }
1348
+ if (charIndex !== termination) {
1349
+ throwError(`Expected ${String.fromCharCode(termination)}`, index);
1350
+ }
1293
1351
  return args;
1294
1352
  }
1295
1353
  function gobbleVariable() {
@@ -1360,28 +1418,41 @@ function parseExpression(expr) {
1360
1418
  };
1361
1419
  }
1362
1420
  const nodes = [];
1363
- while (index < length) {
1364
- const chIndex = exprICode(index);
1365
- if (chIndex === SEMCOL_CODE || chIndex === COMMA_CODE) {
1366
- index++;
1367
- continue;
1421
+ try {
1422
+ while (index < length) {
1423
+ const chIndex = exprICode(index);
1424
+ if (chIndex === SEMCOL_CODE || chIndex === COMMA_CODE) {
1425
+ index++;
1426
+ continue;
1427
+ }
1428
+ const node = gobbleExpression();
1429
+ if (node) {
1430
+ nodes.push(node);
1431
+ } else if (index < length) {
1432
+ throwError(`Unexpected "${exprI(index)}"`, index);
1433
+ }
1368
1434
  }
1369
- const node = gobbleExpression();
1370
- if (node) {
1371
- nodes.push(node);
1372
- } else if (index < length) {
1373
- throwError(`Unexpected "${exprI(index)}"`, index);
1435
+ if (nodes.length === 1) {
1436
+ return nodes[0];
1374
1437
  }
1438
+ return {
1439
+ __id: ExpNodeOpaqueIdentifier,
1440
+ type: "Compound",
1441
+ body: nodes,
1442
+ location: getLocation(0)
1443
+ };
1444
+ } catch (e) {
1445
+ if (strictMode || !(e instanceof Error)) {
1446
+ throw e;
1447
+ }
1448
+ return {
1449
+ __id: ExpNodeOpaqueIdentifier,
1450
+ type: "Compound",
1451
+ body: nodes,
1452
+ location: getLocation(0),
1453
+ error: e
1454
+ };
1375
1455
  }
1376
- if (nodes.length === 1) {
1377
- return nodes[0];
1378
- }
1379
- return {
1380
- __id: ExpNodeOpaqueIdentifier,
1381
- type: "Compound",
1382
- body: nodes,
1383
- location: getLocation(0)
1384
- };
1385
1456
  }
1386
1457
 
1387
1458
  const setDataVal = (_context, binding, value) => {
@@ -1391,16 +1462,108 @@ const getDataVal = (_context, binding) => {
1391
1462
  return _context.model.get(binding);
1392
1463
  };
1393
1464
  const deleteDataVal = (_context, binding) => {
1394
- return _context.model.set([[binding, void 0]]);
1465
+ return _context.model.delete(binding);
1395
1466
  };
1467
+ const conditional = (ctx, condition, ifTrue, ifFalse) => {
1468
+ const resolution = ctx.evaluate(condition);
1469
+ if (resolution) {
1470
+ return ctx.evaluate(ifTrue);
1471
+ }
1472
+ if (ifFalse) {
1473
+ return ctx.evaluate(ifFalse);
1474
+ }
1475
+ return null;
1476
+ };
1477
+ conditional.resolveParams = false;
1396
1478
 
1397
1479
  var DEFAULT_EXPRESSION_HANDLERS = /*#__PURE__*/Object.freeze({
1398
1480
  __proto__: null,
1399
1481
  setDataVal: setDataVal,
1400
1482
  getDataVal: getDataVal,
1401
- deleteDataVal: deleteDataVal
1483
+ deleteDataVal: deleteDataVal,
1484
+ conditional: conditional
1402
1485
  });
1403
1486
 
1487
+ function withoutContext(fn) {
1488
+ return (_context, ...args) => fn(...args);
1489
+ }
1490
+ function isInRange(position, location) {
1491
+ return position.character >= location.start.character && position.character <= location.end.character;
1492
+ }
1493
+ function findClosestNodeAtPosition(node, position) {
1494
+ var _a, _b, _c, _d, _e;
1495
+ switch (node.type) {
1496
+ case "Modification":
1497
+ case "Assignment":
1498
+ case "LogicalExpression":
1499
+ case "BinaryExpression": {
1500
+ const check = (_a = findClosestNodeAtPosition(node.left, position)) != null ? _a : findClosestNodeAtPosition(node.right, position);
1501
+ if (check) {
1502
+ return check;
1503
+ }
1504
+ break;
1505
+ }
1506
+ case "UnaryExpression": {
1507
+ const checkArg = findClosestNodeAtPosition(node.argument, position);
1508
+ if (checkArg) {
1509
+ return checkArg;
1510
+ }
1511
+ break;
1512
+ }
1513
+ case "MemberExpression": {
1514
+ const checkObject = (_b = findClosestNodeAtPosition(node.object, position)) != null ? _b : findClosestNodeAtPosition(node.property, position);
1515
+ if (checkObject) {
1516
+ return checkObject;
1517
+ }
1518
+ break;
1519
+ }
1520
+ case "ConditionalExpression": {
1521
+ const checkObject = (_d = (_c = findClosestNodeAtPosition(node.test, position)) != null ? _c : findClosestNodeAtPosition(node.consequent, position)) != null ? _d : findClosestNodeAtPosition(node.alternate, position);
1522
+ if (checkObject) {
1523
+ return checkObject;
1524
+ }
1525
+ break;
1526
+ }
1527
+ case "ArrayExpression":
1528
+ case "Compound": {
1529
+ const elements = node.type === "ArrayExpression" ? node.elements : node.body;
1530
+ const anyElements = elements.find((e) => findClosestNodeAtPosition(e, position));
1531
+ if (anyElements) {
1532
+ return anyElements;
1533
+ }
1534
+ break;
1535
+ }
1536
+ case "Object": {
1537
+ const checkObject = node.attributes.reduce((found, next) => {
1538
+ var _a2;
1539
+ return (_a2 = found != null ? found : findClosestNodeAtPosition(next.key, position)) != null ? _a2 : findClosestNodeAtPosition(next.value, position);
1540
+ }, void 0);
1541
+ if (checkObject) {
1542
+ return checkObject;
1543
+ }
1544
+ break;
1545
+ }
1546
+ case "CallExpression": {
1547
+ const anyArgs = (_e = node.args.find((arg) => {
1548
+ return findClosestNodeAtPosition(arg, position);
1549
+ })) != null ? _e : findClosestNodeAtPosition(node.callTarget, position);
1550
+ if (anyArgs) {
1551
+ return anyArgs;
1552
+ }
1553
+ break;
1554
+ }
1555
+ }
1556
+ if (node.location && isInRange(position, node.location)) {
1557
+ return node;
1558
+ }
1559
+ }
1560
+ function isObjectExpression(expr) {
1561
+ if (isExpressionNode(expr)) {
1562
+ return false;
1563
+ }
1564
+ return typeof expr === "object" && expr !== null && !Array.isArray(expr) && "value" in expr;
1565
+ }
1566
+
1404
1567
  var __defProp$c = Object.defineProperty;
1405
1568
  var __defProps$a = Object.defineProperties;
1406
1569
  var __getOwnPropDescs$a = Object.getOwnPropertyDescriptors;
@@ -1461,6 +1624,8 @@ class ExpressionEvaluator {
1461
1624
  this.vars = {};
1462
1625
  this.hooks = {
1463
1626
  resolve: new SyncWaterfallHook(),
1627
+ resolveOptions: new SyncWaterfallHook(),
1628
+ beforeEvaluate: new SyncWaterfallHook(),
1464
1629
  onError: new SyncBailHook()
1465
1630
  };
1466
1631
  this.expressionsCache = new Map();
@@ -1479,21 +1644,25 @@ class ExpressionEvaluator {
1479
1644
  reset() {
1480
1645
  this.expressionsCache.clear();
1481
1646
  }
1482
- evaluate(expression, options) {
1483
- const opts = __spreadProps$a(__spreadValues$c(__spreadValues$c({}, this.defaultHookOptions), options), {
1484
- resolveNode: (node) => this._execAST(node, opts)
1485
- });
1647
+ evaluate(expr, options) {
1648
+ var _a;
1649
+ const resolvedOpts = this.hooks.resolveOptions.call(__spreadProps$a(__spreadValues$c(__spreadValues$c({}, this.defaultHookOptions), options), {
1650
+ resolveNode: (node) => this._execAST(node, resolvedOpts)
1651
+ }));
1652
+ let expression = (_a = this.hooks.beforeEvaluate.call(expr, resolvedOpts)) != null ? _a : expr;
1653
+ while (isObjectExpression(expression)) {
1654
+ expression = expression.value;
1655
+ }
1486
1656
  if (typeof expression === "number" || typeof expression === "boolean" || expression === void 0 || expression === null) {
1487
1657
  return expression;
1488
1658
  }
1489
1659
  if (isExpressionNode(expression)) {
1490
- return this._execAST(expression, opts);
1660
+ return this._execAST(expression, resolvedOpts);
1491
1661
  }
1492
- if (typeof expression === "object") {
1493
- const values = Array.isArray(expression) ? expression : Object.values(expression);
1494
- return values.reduce((_nothing, exp) => this.evaluate(exp, options), null);
1662
+ if (Array.isArray(expression)) {
1663
+ return expression.reduce((_nothing, exp) => this.evaluate(exp, options), null);
1495
1664
  }
1496
- return this._execString(String(expression), opts);
1665
+ return this._execString(String(expression), resolvedOpts);
1497
1666
  }
1498
1667
  addExpressionFunction(name, handler) {
1499
1668
  this.operators.expressions.set(name, handler);
@@ -1531,7 +1700,7 @@ class ExpressionEvaluator {
1531
1700
  this.expressionsCache.set(matchedExp, expAST);
1532
1701
  return this._execAST(expAST, options);
1533
1702
  } catch (e) {
1534
- if (!this.hooks.onError.call(e)) {
1703
+ if (options.throwErrors || !this.hooks.onError.call(e)) {
1535
1704
  throw e;
1536
1705
  }
1537
1706
  }
@@ -1585,25 +1754,18 @@ class ExpressionEvaluator {
1585
1754
  }
1586
1755
  if (node.type === "CallExpression") {
1587
1756
  const expressionName = node.callTarget.name;
1588
- if (expressionName === "conditional") {
1589
- const condition = resolveNode(node.args[0]);
1590
- if (condition) {
1591
- return resolveNode(node.args[1]);
1592
- }
1593
- if (node.args[2]) {
1594
- return resolveNode(node.args[2]);
1595
- }
1596
- return null;
1597
- }
1598
1757
  const operator = this.operators.expressions.get(expressionName);
1599
1758
  if (!operator) {
1600
1759
  throw new Error(`Unknown expression function: ${expressionName}`);
1601
1760
  }
1761
+ if ("resolveParams" in operator && operator.resolveParams === false) {
1762
+ return operator(expressionContext, ...node.args);
1763
+ }
1602
1764
  const args = node.args.map((n) => resolveNode(n));
1603
1765
  return operator(expressionContext, ...args);
1604
1766
  }
1605
1767
  if (node.type === "ModelRef") {
1606
- return model.get(node.ref);
1768
+ return model.get(node.ref, { context: { model: options.model } });
1607
1769
  }
1608
1770
  if (node.type === "MemberExpression") {
1609
1771
  const obj = resolveNode(node.object);
@@ -1655,80 +1817,6 @@ class ExpressionEvaluator {
1655
1817
  }
1656
1818
  }
1657
1819
 
1658
- function withoutContext(fn) {
1659
- return (_context, ...args) => fn(...args);
1660
- }
1661
- function isInRange(position, location) {
1662
- return position.character >= location.start.character && position.character <= location.end.character;
1663
- }
1664
- function findClosestNodeAtPosition(node, position) {
1665
- var _a, _b, _c, _d, _e;
1666
- switch (node.type) {
1667
- case "Modification":
1668
- case "Assignment":
1669
- case "LogicalExpression":
1670
- case "BinaryExpression": {
1671
- const check = (_a = findClosestNodeAtPosition(node.left, position)) != null ? _a : findClosestNodeAtPosition(node.right, position);
1672
- if (check) {
1673
- return check;
1674
- }
1675
- break;
1676
- }
1677
- case "UnaryExpression": {
1678
- const checkArg = findClosestNodeAtPosition(node.argument, position);
1679
- if (checkArg) {
1680
- return checkArg;
1681
- }
1682
- break;
1683
- }
1684
- case "MemberExpression": {
1685
- const checkObject = (_b = findClosestNodeAtPosition(node.object, position)) != null ? _b : findClosestNodeAtPosition(node.property, position);
1686
- if (checkObject) {
1687
- return checkObject;
1688
- }
1689
- break;
1690
- }
1691
- case "ConditionalExpression": {
1692
- const checkObject = (_d = (_c = findClosestNodeAtPosition(node.test, position)) != null ? _c : findClosestNodeAtPosition(node.consequent, position)) != null ? _d : findClosestNodeAtPosition(node.alternate, position);
1693
- if (checkObject) {
1694
- return checkObject;
1695
- }
1696
- break;
1697
- }
1698
- case "ArrayExpression":
1699
- case "Compound": {
1700
- const elements = node.type === "ArrayExpression" ? node.elements : node.body;
1701
- const anyElements = elements.find((e) => findClosestNodeAtPosition(e, position));
1702
- if (anyElements) {
1703
- return anyElements;
1704
- }
1705
- break;
1706
- }
1707
- case "Object": {
1708
- const checkObject = node.attributes.reduce((found, next) => {
1709
- var _a2;
1710
- return (_a2 = found != null ? found : findClosestNodeAtPosition(next.key, position)) != null ? _a2 : findClosestNodeAtPosition(next.value, position);
1711
- }, void 0);
1712
- if (checkObject) {
1713
- return checkObject;
1714
- }
1715
- break;
1716
- }
1717
- case "CallExpression": {
1718
- const anyArgs = (_e = node.args.find((arg) => {
1719
- return findClosestNodeAtPosition(arg, position);
1720
- })) != null ? _e : findClosestNodeAtPosition(node.callTarget, position);
1721
- if (anyArgs) {
1722
- return anyArgs;
1723
- }
1724
- break;
1725
- }
1726
- }
1727
- if (node.location && isInRange(position, node.location)) {
1728
- return node;
1729
- }
1730
- }
1731
-
1732
1820
  const severities = ["trace", "debug", "info", "warn", "error"];
1733
1821
 
1734
1822
  class ConsoleLogger {
@@ -1885,6 +1973,9 @@ function parse(schema) {
1885
1973
  if (type.isArray) {
1886
1974
  nestedPath.push("[]");
1887
1975
  }
1976
+ if (type.isRecord) {
1977
+ nestedPath.push("{}");
1978
+ }
1888
1979
  if (type.type && schema[type.type]) {
1889
1980
  parseQueue.push({
1890
1981
  path: nestedPath,
@@ -1933,8 +2024,20 @@ class SchemaController {
1933
2024
  if (cached) {
1934
2025
  return cached;
1935
2026
  }
1936
- const normalized = binding.asArray().map((p) => typeof p === "number" ? "[]" : p).join(".");
1937
- this.bindingSchemaNormalizedCache.set(binding, normalized);
2027
+ let bindingArray = binding.asArray();
2028
+ let normalized = bindingArray.map((p) => typeof p === "number" ? "[]" : p).join(".");
2029
+ if (normalized) {
2030
+ this.bindingSchemaNormalizedCache.set(binding, normalized);
2031
+ bindingArray = normalized.split(".");
2032
+ }
2033
+ bindingArray.forEach((item) => {
2034
+ const recordBinding = bindingArray.map((p) => p === item ? "{}" : p).join(".");
2035
+ if (this.schema.get(recordBinding)) {
2036
+ this.bindingSchemaNormalizedCache.set(binding, recordBinding);
2037
+ bindingArray = recordBinding.split(".");
2038
+ normalized = recordBinding;
2039
+ }
2040
+ });
1938
2041
  return normalized;
1939
2042
  }
1940
2043
  getType(binding) {
@@ -2021,6 +2124,9 @@ function findNextExp(str) {
2021
2124
  };
2022
2125
  }
2023
2126
  function resolveExpressionsInString(val, { evaluate }) {
2127
+ if (!evaluate) {
2128
+ return val;
2129
+ }
2024
2130
  const expMatch = /@\[.*?\]@/;
2025
2131
  let newVal = val;
2026
2132
  let match = newVal.match(expMatch);
@@ -2038,9 +2144,9 @@ function resolveExpressionsInString(val, { evaluate }) {
2038
2144
  return newVal;
2039
2145
  }
2040
2146
  function resolveDataRefsInString(val, options) {
2041
- const { model } = options;
2147
+ const { model, formatted = true } = options;
2042
2148
  let workingString = resolveExpressionsInString(val, options);
2043
- if (typeof workingString !== "string" || workingString.indexOf(DOUBLE_OPEN_CURLY) === -1) {
2149
+ if (!model || typeof workingString !== "string" || workingString.indexOf(DOUBLE_OPEN_CURLY) === -1) {
2044
2150
  return workingString;
2045
2151
  }
2046
2152
  while (workingString.indexOf(DOUBLE_OPEN_CURLY) !== -1) {
@@ -2050,7 +2156,7 @@ function resolveDataRefsInString(val, options) {
2050
2156
  }
2051
2157
  const { start, end } = expLocation;
2052
2158
  const binding = workingString.substring(start + DOUBLE_OPEN_CURLY.length, end - DOUBLE_OPEN_CURLY.length).trim();
2053
- const evaledVal = model.get(binding, { formatted: true });
2159
+ const evaledVal = model.get(binding, { formatted });
2054
2160
  if (start === 0 && end === workingString.length && typeof evaledVal !== "string") {
2055
2161
  return evaledVal;
2056
2162
  }
@@ -2069,9 +2175,9 @@ function traverseObject(val, options) {
2069
2175
  const keys = Object.keys(val);
2070
2176
  let newVal = val;
2071
2177
  if (keys.length > 0) {
2072
- for (const key of keys) {
2178
+ keys.forEach((key) => {
2073
2179
  newVal = setIn(newVal, [key], traverseObject(val[key], options));
2074
- }
2180
+ });
2075
2181
  }
2076
2182
  return newVal;
2077
2183
  }
@@ -2083,6 +2189,36 @@ function resolveDataRefs(val, options) {
2083
2189
  return traverseObject(val, options);
2084
2190
  }
2085
2191
 
2192
+ function removeBindingAndChildrenFromMap(sourceMap, binding) {
2193
+ const targetMap = new Map(sourceMap);
2194
+ const parentBinding = binding.parent();
2195
+ const property = binding.key();
2196
+ targetMap.forEach((_value, trackedBinding) => {
2197
+ if (binding === trackedBinding || binding.contains(trackedBinding)) {
2198
+ targetMap.delete(trackedBinding);
2199
+ }
2200
+ });
2201
+ if (typeof property === "number") {
2202
+ const bindingsToRewrite = Array.from(sourceMap.keys()).filter((b) => {
2203
+ if (parentBinding.contains(b)) {
2204
+ const [childIndex] = b.relative(parentBinding);
2205
+ return typeof childIndex === "number" && childIndex > property;
2206
+ }
2207
+ return false;
2208
+ }).sort();
2209
+ bindingsToRewrite.forEach((trackedBinding) => {
2210
+ const [childIndex, ...childPath] = trackedBinding.relative(parentBinding);
2211
+ if (typeof childIndex === "number") {
2212
+ const newSegments = [childIndex - 1, ...childPath];
2213
+ const newChildBinding = parentBinding.descendent(newSegments);
2214
+ targetMap.set(newChildBinding, targetMap.get(trackedBinding));
2215
+ targetMap.delete(trackedBinding);
2216
+ }
2217
+ });
2218
+ }
2219
+ return targetMap;
2220
+ }
2221
+
2086
2222
  var __defProp$a = Object.defineProperty;
2087
2223
  var __defProps$8 = Object.defineProperties;
2088
2224
  var __getOwnPropDescs$8 = Object.getOwnPropertyDescriptors;
@@ -2107,12 +2243,15 @@ class ValidationMiddleware {
2107
2243
  this.validator = validator;
2108
2244
  this.shadowModelPaths = new Map();
2109
2245
  this.logger = options == null ? void 0 : options.logger;
2246
+ this.shouldIncludeInvalid = options == null ? void 0 : options.shouldIncludeInvalid;
2110
2247
  }
2111
2248
  set(transaction, options, next) {
2112
2249
  const asModel = toModel(this, __spreadProps$8(__spreadValues$a({}, options), { includeInvalid: true }), next);
2113
2250
  const nextTransaction = [];
2251
+ const includedBindings = new Set();
2114
2252
  transaction.forEach(([binding, value]) => {
2115
2253
  this.shadowModelPaths.set(binding, value);
2254
+ includedBindings.add(binding);
2116
2255
  });
2117
2256
  const invalidBindings = [];
2118
2257
  this.shadowModelPaths.forEach((value, binding) => {
@@ -2123,22 +2262,25 @@ class ValidationMiddleware {
2123
2262
  } else if (validations instanceof Set) {
2124
2263
  validations.forEach((validation) => {
2125
2264
  invalidBindings.push(validation.binding);
2126
- if (!validation.isStrong) {
2265
+ if (!validation.isStrong && validation.binding.asString() === binding.asString()) {
2127
2266
  nextTransaction.push([validation.binding, value]);
2128
2267
  }
2129
2268
  });
2130
- } else {
2269
+ } else if (includedBindings.has(binding)) {
2270
+ invalidBindings.push(binding);
2131
2271
  (_a = this.logger) == null ? void 0 : _a.debug(`Invalid value for path: ${binding.asString()} - ${validations.severity} - ${validations.message}`);
2132
2272
  }
2133
2273
  });
2274
+ let validResults = [];
2134
2275
  if (next && nextTransaction.length > 0) {
2135
2276
  nextTransaction.forEach(([binding]) => this.shadowModelPaths.delete(binding));
2136
2277
  const result = next.set(nextTransaction, options);
2137
2278
  if (invalidBindings.length === 0) {
2138
2279
  return result;
2139
2280
  }
2281
+ validResults = result;
2140
2282
  }
2141
- return invalidBindings.map((binding) => {
2283
+ const invalidResults = invalidBindings.map((binding) => {
2142
2284
  return {
2143
2285
  binding,
2144
2286
  oldValue: asModel.get(binding),
@@ -2146,10 +2288,12 @@ class ValidationMiddleware {
2146
2288
  force: true
2147
2289
  };
2148
2290
  });
2291
+ return [...validResults, ...invalidResults];
2149
2292
  }
2150
2293
  get(binding, options, next) {
2294
+ var _a, _b;
2151
2295
  let val = next == null ? void 0 : next.get(binding, options);
2152
- if ((options == null ? void 0 : options.includeInvalid) === true) {
2296
+ if ((_b = (_a = this.shouldIncludeInvalid) == null ? void 0 : _a.call(this, options)) != null ? _b : (options == null ? void 0 : options.includeInvalid) === true) {
2153
2297
  this.shadowModelPaths.forEach((shadowValue, shadowBinding) => {
2154
2298
  if (shadowBinding === binding) {
2155
2299
  val = shadowValue;
@@ -2162,6 +2306,10 @@ class ValidationMiddleware {
2162
2306
  }
2163
2307
  return val;
2164
2308
  }
2309
+ delete(binding, options, next) {
2310
+ this.shadowModelPaths = removeBindingAndChildrenFromMap(this.shadowModelPaths, binding);
2311
+ return next == null ? void 0 : next.delete(binding, options);
2312
+ }
2165
2313
  }
2166
2314
 
2167
2315
  class ValidatorRegistry {
@@ -2246,6 +2394,9 @@ class Parser {
2246
2394
  }
2247
2395
  return tapped;
2248
2396
  }
2397
+ hasTemplateValues(obj, localKey) {
2398
+ return Object.hasOwnProperty.call(obj, "template") && Array.isArray(obj == null ? void 0 : obj.template) && obj.template.length && obj.template.find((tmpl) => tmpl.output === localKey);
2399
+ }
2249
2400
  parseObject(obj, type = NodeType.Value, options = { templateDepth: 0 }) {
2250
2401
  var _a;
2251
2402
  const nodeType = this.hooks.determineNodeType.call(obj);
@@ -2263,12 +2414,19 @@ class Parser {
2263
2414
  if (!localObj) {
2264
2415
  return currentValue;
2265
2416
  }
2266
- const objEntries = Array.isArray(localObj) ? localObj.map((v, i) => [i, v]) : Object.entries(localObj);
2417
+ const objEntries = Array.isArray(localObj) ? localObj.map((v, i) => [i, v]) : [
2418
+ ...Object.entries(localObj),
2419
+ ...Object.getOwnPropertySymbols(localObj).map((s) => [
2420
+ s,
2421
+ localObj[s]
2422
+ ])
2423
+ ];
2267
2424
  const defaultValue = {
2268
2425
  children: [],
2269
2426
  value: currentValue
2270
2427
  };
2271
2428
  const newValue = objEntries.reduce((accumulation, current) => {
2429
+ var _b;
2272
2430
  const _a2 = accumulation, { children: children2 } = _a2, rest = __objRest$1(_a2, ["children"]);
2273
2431
  const [localKey, localValue] = current;
2274
2432
  if (localKey === "asset" && typeof localValue === "object") {
@@ -2286,14 +2444,19 @@ class Parser {
2286
2444
  }
2287
2445
  } else if (this.hooks.determineNodeType.call(localKey) === NodeType.Template && Array.isArray(localValue)) {
2288
2446
  const templateChildren = localValue.map((template) => {
2289
- var _a3, _b;
2447
+ var _a3, _b2;
2290
2448
  const templateAST = this.hooks.onCreateASTNode.call({
2291
2449
  type: NodeType.Template,
2292
2450
  depth: (_a3 = options.templateDepth) != null ? _a3 : 0,
2293
2451
  data: template.data,
2294
2452
  template: template.value,
2295
- dynamic: (_b = template.dynamic) != null ? _b : false
2453
+ dynamic: (_b2 = template.dynamic) != null ? _b2 : false
2296
2454
  }, template);
2455
+ if ((templateAST == null ? void 0 : templateAST.type) === NodeType.MultiNode) {
2456
+ templateAST.values.forEach((v) => {
2457
+ v.parent = templateAST;
2458
+ });
2459
+ }
2297
2460
  if (templateAST) {
2298
2461
  return {
2299
2462
  path: [...path, template.output],
@@ -2307,6 +2470,18 @@ class Parser {
2307
2470
  });
2308
2471
  } else if (localValue && this.hooks.determineNodeType.call(localValue) === NodeType.Switch) {
2309
2472
  const localSwitch = this.hooks.parseNode.call(localValue, NodeType.Value, options, NodeType.Switch);
2473
+ if (localSwitch && localSwitch.type === NodeType.Value && ((_b = localSwitch.children) == null ? void 0 : _b.length) === 1 && localSwitch.value === void 0) {
2474
+ const firstChild = localSwitch.children[0];
2475
+ return __spreadProps$7(__spreadValues$9({}, rest), {
2476
+ children: [
2477
+ ...children2,
2478
+ {
2479
+ path: [...path, localKey, ...firstChild.path],
2480
+ value: firstChild.value
2481
+ }
2482
+ ]
2483
+ });
2484
+ }
2310
2485
  if (localSwitch) {
2311
2486
  return __spreadProps$7(__spreadValues$9({}, rest), {
2312
2487
  children: [
@@ -2323,7 +2498,7 @@ class Parser {
2323
2498
  if (childValues.length > 0) {
2324
2499
  const multiNode = this.hooks.onCreateASTNode.call({
2325
2500
  type: NodeType.MultiNode,
2326
- override: true,
2501
+ override: !this.hasTemplateValues(localObj, localKey),
2327
2502
  values: childValues
2328
2503
  }, localValue);
2329
2504
  if ((multiNode == null ? void 0 : multiNode.type) === NodeType.MultiNode) {
@@ -2346,7 +2521,7 @@ class Parser {
2346
2521
  } else if (localValue && typeof localValue === "object") {
2347
2522
  const determineNodeType = this.hooks.determineNodeType.call(localValue);
2348
2523
  if (determineNodeType === NodeType.Applicability) {
2349
- const parsedNode = this.hooks.parseNode.call(localValue, type, options, determineNodeType);
2524
+ const parsedNode = this.hooks.parseNode.call(localValue, NodeType.Value, options, determineNodeType);
2350
2525
  if (parsedNode) {
2351
2526
  return __spreadProps$7(__spreadValues$9({}, rest), {
2352
2527
  children: [
@@ -2468,6 +2643,11 @@ const withContext = (model) => {
2468
2643
  return model.set(transaction, __spreadValues$7({
2469
2644
  context: { model }
2470
2645
  }, options));
2646
+ },
2647
+ delete: (binding, options) => {
2648
+ return model.delete(binding, __spreadValues$7({
2649
+ context: { model }
2650
+ }, options));
2471
2651
  }
2472
2652
  };
2473
2653
  };
@@ -2497,12 +2677,16 @@ class Resolver {
2497
2677
  this.hooks.beforeUpdate.call(changes);
2498
2678
  const resolveCache = new Map();
2499
2679
  this.idCache.clear();
2680
+ const prevASTMap = new Map(this.ASTMap);
2500
2681
  this.ASTMap.clear();
2501
- const updated = this.computeTree(this.root, void 0, changes, resolveCache, toNodeResolveOptions(this.options));
2682
+ const updated = this.computeTree(this.root, void 0, changes, resolveCache, toNodeResolveOptions(this.options), void 0, prevASTMap);
2502
2683
  this.resolveCache = resolveCache;
2503
2684
  this.hooks.afterUpdate.call(updated.value);
2504
2685
  return updated.value;
2505
2686
  }
2687
+ getResolveCache() {
2688
+ return new Map(this.resolveCache);
2689
+ }
2506
2690
  getNodeID(node) {
2507
2691
  var _a;
2508
2692
  if (!node) {
@@ -2534,7 +2718,19 @@ class Resolver {
2534
2718
  }
2535
2719
  return this.resolveCache.get(node);
2536
2720
  }
2537
- computeTree(node, parent, dataChanges, cacheUpdate, options) {
2721
+ cloneNode(node) {
2722
+ const clonedNode = clone(node);
2723
+ Object.keys(clonedNode).forEach((key) => {
2724
+ if (key === "parent")
2725
+ return;
2726
+ const value = clonedNode[key];
2727
+ if (typeof value === "object" && value !== null) {
2728
+ clonedNode[key] = Array.isArray(value) ? [...value] : __spreadValues$7({}, value);
2729
+ }
2730
+ });
2731
+ return clonedNode;
2732
+ }
2733
+ computeTree(node, parent, dataChanges, cacheUpdate, options, parentNode, prevASTMap) {
2538
2734
  var _a, _b;
2539
2735
  const dependencyModel = new DependencyModel(options.data.model);
2540
2736
  dependencyModel.trackSubset("core");
@@ -2555,34 +2751,40 @@ class Resolver {
2555
2751
  updated: false
2556
2752
  });
2557
2753
  cacheUpdate.set(node, update2);
2558
- const repopulateASTMapFromCache = (resolvedAST3, AST) => {
2754
+ const repopulateASTMapFromCache = (resolvedNode, AST, ASTParent) => {
2559
2755
  var _a2;
2560
- this.ASTMap.set(resolvedAST3, AST);
2561
- if ("children" in resolvedAST3) {
2562
- (_a2 = resolvedAST3.children) == null ? void 0 : _a2.forEach(({ value: childAST }) => {
2563
- const { node: childResolvedAST } = this.getPreviousResult(childAST) || {};
2564
- if (!childResolvedAST)
2565
- return;
2566
- repopulateASTMapFromCache(childResolvedAST, childAST);
2567
- if (childResolvedAST.type === NodeType.MultiNode) {
2568
- childResolvedAST.values.forEach((mChildAST) => {
2569
- const { node: mChildResolvedAST } = this.getPreviousResult(mChildAST) || {};
2570
- if (!mChildResolvedAST)
2571
- return;
2572
- repopulateASTMapFromCache(mChildResolvedAST, mChildAST);
2573
- });
2574
- }
2575
- });
2756
+ const { node: resolvedAST2 } = resolvedNode;
2757
+ this.ASTMap.set(resolvedAST2, AST);
2758
+ const resolvedUpdate = __spreadProps$5(__spreadValues$7({}, resolvedNode), {
2759
+ updated: false
2760
+ });
2761
+ cacheUpdate.set(AST, resolvedUpdate);
2762
+ const handleChildNode = (childNode) => {
2763
+ var _a3;
2764
+ const originalChildNode = (_a3 = prevASTMap.get(childNode)) != null ? _a3 : childNode;
2765
+ const previousChildResult = this.getPreviousResult(originalChildNode);
2766
+ if (!previousChildResult)
2767
+ return;
2768
+ repopulateASTMapFromCache(previousChildResult, originalChildNode, AST);
2769
+ };
2770
+ if ("children" in resolvedAST2) {
2771
+ (_a2 = resolvedAST2.children) == null ? void 0 : _a2.forEach(({ value: childAST }) => handleChildNode(childAST));
2772
+ } else if (resolvedAST2.type === NodeType.MultiNode) {
2773
+ resolvedAST2.values.forEach(handleChildNode);
2576
2774
  }
2775
+ this.hooks.afterNodeUpdate.call(AST, ASTParent, resolvedUpdate);
2577
2776
  };
2578
- const resolvedAST2 = previousResult.node;
2579
- repopulateASTMapFromCache(resolvedAST2, node);
2580
- this.hooks.afterNodeUpdate.call(node, parent, update2);
2777
+ previousResult.node.parent = parentNode;
2778
+ repopulateASTMapFromCache(previousResult, node, parent);
2581
2779
  return update2;
2582
2780
  }
2583
- const resolvedAST = (_a = this.hooks.beforeResolve.call(node, resolveOptions)) != null ? _a : {
2781
+ const clonedNode = __spreadProps$5(__spreadValues$7({}, this.cloneNode(node)), {
2782
+ parent: parentNode
2783
+ });
2784
+ const resolvedAST = (_a = this.hooks.beforeResolve.call(clonedNode, resolveOptions)) != null ? _a : {
2584
2785
  type: NodeType.Empty
2585
2786
  };
2787
+ resolvedAST.parent = parentNode;
2586
2788
  resolveOptions.node = resolvedAST;
2587
2789
  this.ASTMap.set(resolvedAST, node);
2588
2790
  let resolved = this.hooks.resolve.call(void 0, resolvedAST, resolveOptions);
@@ -2593,22 +2795,15 @@ class Resolver {
2593
2795
  const childDependencies = new Set();
2594
2796
  dependencyModel.trackSubset("children");
2595
2797
  if ("children" in resolvedAST) {
2596
- (_b = resolvedAST.children) == null ? void 0 : _b.forEach((child) => {
2597
- const computedChildTree = this.computeTree(child.value, node, dataChanges, cacheUpdate, resolveOptions);
2598
- let { updated: childUpdated, value: childValue } = computedChildTree;
2599
- const { node: childNode, dependencies: childTreeDeps } = computedChildTree;
2798
+ const newChildren = (_b = resolvedAST.children) == null ? void 0 : _b.map((child) => {
2799
+ const computedChildTree = this.computeTree(child.value, node, dataChanges, cacheUpdate, resolveOptions, resolvedAST, prevASTMap);
2800
+ const {
2801
+ dependencies: childTreeDeps,
2802
+ node: childNode,
2803
+ updated: childUpdated,
2804
+ value: childValue
2805
+ } = computedChildTree;
2600
2806
  childTreeDeps.forEach((binding) => childDependencies.add(binding));
2601
- if (childNode.type === NodeType.MultiNode) {
2602
- childValue = [];
2603
- childNode.values.forEach((mValue) => {
2604
- const mTree = this.computeTree(mValue, node, dataChanges, cacheUpdate, resolveOptions);
2605
- if (mTree.value !== void 0 && mTree.value !== null) {
2606
- childValue.push(mTree.value);
2607
- }
2608
- mTree.dependencies.forEach((bindingDep) => childDependencies.add(bindingDep));
2609
- childUpdated = childUpdated || mTree.updated;
2610
- });
2611
- }
2612
2807
  if (childValue) {
2613
2808
  if (childNode.type === NodeType.MultiNode && !childNode.override) {
2614
2809
  const arr = addLast(get(resolved, child.path, []), childValue);
@@ -2618,7 +2813,22 @@ class Resolver {
2618
2813
  }
2619
2814
  }
2620
2815
  updated = updated || childUpdated;
2816
+ return __spreadProps$5(__spreadValues$7({}, child), { value: childNode });
2621
2817
  });
2818
+ resolvedAST.children = newChildren;
2819
+ } else if (resolvedAST.type === NodeType.MultiNode) {
2820
+ const childValue = [];
2821
+ const newValues = resolvedAST.values.map((mValue) => {
2822
+ const mTree = this.computeTree(mValue, node, dataChanges, cacheUpdate, resolveOptions, resolvedAST, prevASTMap);
2823
+ if (mTree.value !== void 0 && mTree.value !== null) {
2824
+ childValue.push(mTree.value);
2825
+ }
2826
+ mTree.dependencies.forEach((bindingDep) => childDependencies.add(bindingDep));
2827
+ updated = updated || mTree.updated;
2828
+ return mTree.node;
2829
+ });
2830
+ resolvedAST.values = newValues;
2831
+ resolved = childValue;
2622
2832
  }
2623
2833
  childDependencies.forEach((bindingDep) => dependencyModel.addChildReadDep(bindingDep));
2624
2834
  dependencyModel.trackSubset("core");
@@ -2687,13 +2897,10 @@ class TemplatePlugin {
2687
2897
  }
2688
2898
  });
2689
2899
  const result = {
2690
- parent: node.parent,
2691
2900
  type: NodeType.MultiNode,
2901
+ override: false,
2692
2902
  values
2693
2903
  };
2694
- result.values.forEach((innerNode) => {
2695
- innerNode.parent = result;
2696
- });
2697
2904
  return result;
2698
2905
  }
2699
2906
  applyParser(parser) {
@@ -2787,19 +2994,20 @@ function resolveAllRefs(node, resolveOptions, propertiesToSkip) {
2787
2994
  });
2788
2995
  return newNode;
2789
2996
  }
2790
- const findBasePath = (node) => {
2997
+ const findBasePath = (node, resolver) => {
2791
2998
  var _a, _b, _c;
2792
2999
  const parentNode = node.parent;
2793
3000
  if (!parentNode) {
2794
3001
  return [];
2795
3002
  }
2796
3003
  if ("children" in parentNode) {
2797
- return (_c = (_b = (_a = parentNode.children) == null ? void 0 : _a.find((child) => child.value === node)) == null ? void 0 : _b.path) != null ? _c : [];
3004
+ const original = resolver.getSourceNode(node);
3005
+ return (_c = (_b = (_a = parentNode.children) == null ? void 0 : _a.find((child) => child.value === original)) == null ? void 0 : _b.path) != null ? _c : [];
2798
3006
  }
2799
3007
  if (parentNode.type !== NodeType.MultiNode) {
2800
3008
  return [];
2801
3009
  }
2802
- return findBasePath(parentNode);
3010
+ return findBasePath(parentNode, resolver);
2803
3011
  };
2804
3012
  class StringResolverPlugin {
2805
3013
  constructor() {
@@ -2823,7 +3031,7 @@ class StringResolverPlugin {
2823
3031
  } else {
2824
3032
  propsToSkip = new Set(["exp"]);
2825
3033
  }
2826
- const nodePath = findBasePath(node);
3034
+ const nodePath = findBasePath(node, resolver);
2827
3035
  if (nodePath.length > 0 && nodePath.some((segment) => propsToSkip.has(segment.toString()))) {
2828
3036
  return node.value;
2829
3037
  }
@@ -2843,7 +3051,7 @@ class ApplicabilityPlugin {
2843
3051
  let newNode = node;
2844
3052
  if ((node == null ? void 0 : node.type) === NodeType.Applicability) {
2845
3053
  const isApplicable = options.evaluate(node.expression);
2846
- if (!isApplicable) {
3054
+ if (isApplicable === false) {
2847
3055
  return null;
2848
3056
  }
2849
3057
  newNode = node.value;
@@ -3149,7 +3357,8 @@ class FlowInstance {
3149
3357
  skipTransition: new SyncBailHook(),
3150
3358
  beforeTransition: new SyncWaterfallHook(),
3151
3359
  resolveTransitionNode: new SyncWaterfallHook(),
3152
- transition: new SyncHook()
3360
+ transition: new SyncHook(),
3361
+ afterTransition: new SyncHook()
3153
3362
  };
3154
3363
  this.id = id;
3155
3364
  this.flow = flow;
@@ -3196,7 +3405,7 @@ class FlowInstance {
3196
3405
  } else {
3197
3406
  const skipTransition = this.hooks.skipTransition.call(this.currentState);
3198
3407
  if (skipTransition) {
3199
- (_d = this.log) == null ? void 0 : _d.debug(`Skipping transition from ${this.currentState} b/c hook told us to`);
3408
+ (_d = this.log) == null ? void 0 : _d.debug(`Skipping transition from ${this.currentState.name} b/c hook told us to`);
3200
3409
  return;
3201
3410
  }
3202
3411
  }
@@ -3235,6 +3444,7 @@ class FlowInstance {
3235
3444
  this.hooks.onEnd.call(this.flow.onEnd);
3236
3445
  }
3237
3446
  this.hooks.transition.call(prevState, __spreadValues$5({}, newCurrentState));
3447
+ this.hooks.afterTransition.call(this);
3238
3448
  }
3239
3449
  }
3240
3450
 
@@ -3269,6 +3479,7 @@ class FlowController {
3269
3479
  this.start = this.start.bind(this);
3270
3480
  this.run = this.run.bind(this);
3271
3481
  this.transition = this.transition.bind(this);
3482
+ this.addNewFlow = this.addNewFlow.bind(this);
3272
3483
  }
3273
3484
  transition(stateTransition, options) {
3274
3485
  if (this.current === void 0) {
@@ -3277,20 +3488,9 @@ class FlowController {
3277
3488
  this.current.transition(stateTransition, options);
3278
3489
  }
3279
3490
  addNewFlow(flow) {
3280
- return __async$1(this, null, function* () {
3281
- this.navStack.push(flow);
3282
- this.current = flow;
3283
- flow.hooks.transition.tap("flow-controller", (_oldState, newState) => __async$1(this, null, function* () {
3284
- var _a, _b;
3285
- if (newState.value.state_type === "FLOW") {
3286
- (_a = this.log) == null ? void 0 : _a.debug(`Got FLOW state. Loading flow ${newState.value.ref}`);
3287
- const endState = yield this.run(newState.value.ref);
3288
- (_b = this.log) == null ? void 0 : _b.debug(`Flow ended. Using outcome: ${endState.outcome}`);
3289
- flow.transition(endState.outcome);
3290
- }
3291
- }));
3292
- this.hooks.flow.call(flow);
3293
- });
3491
+ this.navStack.push(flow);
3492
+ this.current = flow;
3493
+ this.hooks.flow.call(flow);
3294
3494
  }
3295
3495
  run(startState) {
3296
3496
  return __async$1(this, null, function* () {
@@ -3305,6 +3505,18 @@ class FlowController {
3305
3505
  (_a = this.log) == null ? void 0 : _a.debug(`Starting flow: ${startState}`);
3306
3506
  const flow = new FlowInstance(startState, startFlow, { logger: this.log });
3307
3507
  this.addNewFlow(flow);
3508
+ flow.hooks.afterTransition.tap("flow-controller", (flowInstance) => {
3509
+ var _a2, _b, _c;
3510
+ if (((_a2 = flowInstance.currentState) == null ? void 0 : _a2.value.state_type) === "FLOW") {
3511
+ const subflowId = (_b = flowInstance.currentState) == null ? void 0 : _b.value.ref;
3512
+ (_c = this.log) == null ? void 0 : _c.debug(`Loading subflow ${subflowId}`);
3513
+ this.run(subflowId).then((subFlowEndState) => {
3514
+ var _a3;
3515
+ (_a3 = this.log) == null ? void 0 : _a3.debug(`Subflow ended. Using outcome: ${subFlowEndState.outcome}`);
3516
+ flowInstance.transition(subFlowEndState == null ? void 0 : subFlowEndState.outcome);
3517
+ });
3518
+ }
3519
+ });
3308
3520
  const end = yield flow.start();
3309
3521
  this.navStack.pop();
3310
3522
  if (this.navStack.length > 0) {
@@ -3357,11 +3569,18 @@ class ValidationBindingTrackerViewPlugin {
3357
3569
  getBindings() {
3358
3570
  return this.trackedBindings;
3359
3571
  }
3572
+ trackBinding(binding) {
3573
+ var _a, _b;
3574
+ if (this.trackedBindings.has(binding)) {
3575
+ return;
3576
+ }
3577
+ this.trackedBindings.add(binding);
3578
+ (_b = (_a = this.options.callbacks) == null ? void 0 : _a.onAdd) == null ? void 0 : _b.call(_a, binding);
3579
+ }
3360
3580
  applyResolver(resolver) {
3361
3581
  this.trackedBindings.clear();
3362
3582
  const tracked = new Map();
3363
3583
  const sections = new Map();
3364
- const seenBindings = new Set();
3365
3584
  let lastViewUpdateChangeSet;
3366
3585
  const nodeTree = new Map();
3367
3586
  let lastComputedBindingTree = new Map();
@@ -3408,31 +3627,34 @@ class ValidationBindingTrackerViewPlugin {
3408
3627
  parent = parent.parent;
3409
3628
  }
3410
3629
  }
3411
- if (!seenBindings.has(parsed)) {
3412
- seenBindings.add(parsed);
3413
- (_d = (_c = this.options.callbacks) == null ? void 0 : _c.onAdd) == null ? void 0 : _d.call(_c, parsed);
3414
- }
3630
+ this.trackedBindings.add(parsed);
3631
+ (_d = (_c = this.options.callbacks) == null ? void 0 : _c.onAdd) == null ? void 0 : _d.call(_c, parsed);
3415
3632
  };
3416
3633
  return __spreadProps$3(__spreadValues$4({}, options), {
3417
3634
  validation: __spreadProps$3(__spreadValues$4({}, options.validation), {
3418
3635
  get: (binding, getOptions) => {
3419
- var _a;
3636
+ var _a, _b;
3420
3637
  if (getOptions == null ? void 0 : getOptions.track) {
3421
3638
  track(binding);
3422
3639
  }
3423
- const eow = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding);
3424
- if ((eow == null ? void 0 : eow.displayTarget) === void 0 || (eow == null ? void 0 : eow.displayTarget) === "field") {
3425
- return eow;
3640
+ const eows = (_b = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding)) == null ? void 0 : _b.getAll(getOptions);
3641
+ const firstFieldEOW = eows == null ? void 0 : eows.find((eow) => eow.displayTarget === "field" || eow.displayTarget === void 0);
3642
+ return firstFieldEOW;
3643
+ },
3644
+ getValidationsForBinding(binding, getOptions) {
3645
+ var _a, _b, _c;
3646
+ if (getOptions == null ? void 0 : getOptions.track) {
3647
+ track(binding);
3426
3648
  }
3427
- return void 0;
3649
+ return (_c = (_b = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding)) == null ? void 0 : _b.getAll(getOptions)) != null ? _c : [];
3428
3650
  },
3429
3651
  getChildren: (type) => {
3430
3652
  var _a;
3431
3653
  const validations = new Array();
3432
3654
  (_a = lastComputedBindingTree.get(node)) == null ? void 0 : _a.forEach((binding) => {
3433
- var _a2;
3434
- const eow = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding);
3435
- if (eow && type === eow.displayTarget) {
3655
+ var _a2, _b;
3656
+ const eow = (_b = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding)) == null ? void 0 : _b.get();
3657
+ if (eow && (type === void 0 || type === eow.displayTarget)) {
3436
3658
  validations.push(eow);
3437
3659
  }
3438
3660
  });
@@ -3442,8 +3664,8 @@ class ValidationBindingTrackerViewPlugin {
3442
3664
  var _a;
3443
3665
  const validations = new Array();
3444
3666
  (_a = lastSectionBindingTree.get(node)) == null ? void 0 : _a.forEach((binding) => {
3445
- var _a2;
3446
- const eow = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding);
3667
+ var _a2, _b;
3668
+ const eow = (_b = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding)) == null ? void 0 : _b.get();
3447
3669
  if (eow && eow.displayTarget === "section") {
3448
3670
  validations.push(eow);
3449
3671
  }
@@ -3462,7 +3684,7 @@ class ValidationBindingTrackerViewPlugin {
3462
3684
  });
3463
3685
  });
3464
3686
  resolver.hooks.afterNodeUpdate.tap(CONTEXT, (node, parent, update) => {
3465
- var _a, _b, _c;
3687
+ var _a, _b;
3466
3688
  if (parent) {
3467
3689
  addToTree(node, parent);
3468
3690
  }
@@ -3477,7 +3699,7 @@ class ValidationBindingTrackerViewPlugin {
3477
3699
  currentBindingTree.set(node, (_b = lastComputedBindingTree.get(node)) != null ? _b : new Set());
3478
3700
  }
3479
3701
  if (node === resolver.root) {
3480
- this.trackedBindings = (_c = currentBindingTree.get(node)) != null ? _c : new Set();
3702
+ this.trackedBindings = new Set(currentBindingTree.get(node));
3481
3703
  lastComputedBindingTree = currentBindingTree;
3482
3704
  lastSectionBindingTree.clear();
3483
3705
  sections.forEach((nodeSet, sectionNode) => {
@@ -3519,11 +3741,15 @@ var __spreadValues$3 = (a, b) => {
3519
3741
  return a;
3520
3742
  };
3521
3743
  var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
3744
+ const SCHEMA_VALIDATION_PROVIDER_NAME = "schema";
3745
+ const VIEW_VALIDATION_PROVIDER_NAME = "view";
3746
+ const VALIDATION_PROVIDER_NAME_SYMBOL = Symbol.for("validation-provider-name");
3522
3747
  function createStatefulValidationObject(obj) {
3523
3748
  return {
3524
3749
  value: obj,
3525
3750
  type: obj.severity,
3526
- state: "none"
3751
+ state: "none",
3752
+ isBlockingNavigation: false
3527
3753
  };
3528
3754
  }
3529
3755
  class ValidatedBinding {
@@ -3538,20 +3764,45 @@ class ValidatedBinding {
3538
3764
  possibleValidations.forEach((vObj) => {
3539
3765
  const { trigger } = vObj;
3540
3766
  if (this.validationsByState[trigger]) {
3541
- this.validationsByState[trigger].push(createStatefulValidationObject(vObj));
3767
+ const statefulValidationObject = createStatefulValidationObject(vObj);
3768
+ this.validationsByState[trigger].push(statefulValidationObject);
3542
3769
  } else {
3543
3770
  log == null ? void 0 : log.warn(`Unknown validation trigger: ${trigger}`);
3544
3771
  }
3545
3772
  });
3546
3773
  this.weakBindings = weakBindings != null ? weakBindings : new Set();
3547
3774
  }
3775
+ get allValidations() {
3776
+ return Object.values(this.validationsByState).flat();
3777
+ }
3778
+ checkIfBlocking(statefulObj) {
3779
+ if (statefulObj.state === "active") {
3780
+ const { isBlockingNavigation } = statefulObj;
3781
+ return isBlockingNavigation;
3782
+ }
3783
+ return false;
3784
+ }
3785
+ getAll() {
3786
+ return this.applicableValidations.reduce((all, statefulObj) => {
3787
+ if (statefulObj.state === "active" && statefulObj.response) {
3788
+ return [
3789
+ ...all,
3790
+ __spreadProps$2(__spreadValues$3({}, statefulObj.response), {
3791
+ blocking: this.checkIfBlocking(statefulObj)
3792
+ })
3793
+ ];
3794
+ }
3795
+ return all;
3796
+ }, []);
3797
+ }
3548
3798
  get() {
3549
- const firstError = this.applicableValidations.find((statefulObj) => {
3550
- const blocking = this.currentPhase === "navigation" ? statefulObj.value.blocking : true;
3551
- return statefulObj.state === "active" && blocking !== false;
3799
+ const firstInvalid = this.applicableValidations.find((statefulObj) => {
3800
+ return statefulObj.state === "active" && statefulObj.response;
3552
3801
  });
3553
- if ((firstError == null ? void 0 : firstError.state) === "active") {
3554
- return firstError.response;
3802
+ if ((firstInvalid == null ? void 0 : firstInvalid.state) === "active") {
3803
+ return __spreadProps$2(__spreadValues$3({}, firstInvalid.response), {
3804
+ blocking: this.checkIfBlocking(firstInvalid)
3805
+ });
3555
3806
  }
3556
3807
  }
3557
3808
  runApplicableValidations(runner, canDismiss) {
@@ -3560,7 +3811,8 @@ class ValidatedBinding {
3560
3811
  if (obj.state === "dismissed") {
3561
3812
  return obj;
3562
3813
  }
3563
- const blocking = (_a = obj.value.blocking) != null ? _a : obj.value.severity === "warning" && "once" || obj.value.severity === "error" && true;
3814
+ const blocking = (_a = obj.value.blocking) != null ? _a : obj.value.severity === "warning" && "once" || true;
3815
+ const isBlockingNavigation = blocking === true || blocking === "once" && !canDismiss;
3564
3816
  const dismissable = canDismiss && blocking === "once";
3565
3817
  if (this.currentPhase === "navigation" && obj.state === "active" && dismissable) {
3566
3818
  if (obj.value.severity === "warning") {
@@ -3572,17 +3824,13 @@ class ValidatedBinding {
3572
3824
  }
3573
3825
  return obj;
3574
3826
  }
3575
- if (obj.value.severity === "error") {
3576
- const err = obj;
3577
- err.state = "none";
3578
- return obj;
3579
- }
3580
3827
  }
3581
3828
  const response = runner(obj.value);
3582
3829
  const newState = {
3583
3830
  type: obj.type,
3584
3831
  value: obj.value,
3585
3832
  state: response ? "active" : "none",
3833
+ isBlockingNavigation,
3586
3834
  dismissable: obj.value.severity === "warning" && this.currentPhase === "navigation",
3587
3835
  response: response ? __spreadProps$2(__spreadValues$3({}, obj.value), {
3588
3836
  message: (_b = response.message) != null ? _b : "Something is broken",
@@ -3633,20 +3881,34 @@ class ValidationController {
3633
3881
  this.hooks = {
3634
3882
  createValidatorRegistry: new SyncHook(),
3635
3883
  onAddValidation: new SyncWaterfallHook(),
3636
- onRemoveValidation: new SyncWaterfallHook()
3884
+ onRemoveValidation: new SyncWaterfallHook(),
3885
+ resolveValidationProviders: new SyncWaterfallHook(),
3886
+ onTrackBinding: new SyncHook()
3637
3887
  };
3638
3888
  this.validations = new Map();
3639
3889
  this.weakBindingTracker = new Set();
3640
- this.lastActiveBindings = new Set();
3641
3890
  this.schema = schema;
3642
3891
  this.options = options;
3643
- this.providers = [schema];
3892
+ this.reset();
3644
3893
  }
3645
3894
  setOptions(options) {
3646
3895
  this.options = options;
3647
3896
  }
3648
3897
  getDataMiddleware() {
3649
3898
  return [
3899
+ {
3900
+ set: (transaction, options, next) => {
3901
+ var _a;
3902
+ return (_a = next == null ? void 0 : next.set(transaction, options)) != null ? _a : [];
3903
+ },
3904
+ get: (binding, options, next) => {
3905
+ return next == null ? void 0 : next.get(binding, options);
3906
+ },
3907
+ delete: (binding, options, next) => {
3908
+ this.validations = removeBindingAndChildrenFromMap(this.validations, binding);
3909
+ return next == null ? void 0 : next.delete(binding, options);
3910
+ }
3911
+ },
3650
3912
  new ValidationMiddleware((binding) => {
3651
3913
  var _a;
3652
3914
  if (!this.options) {
@@ -3662,13 +3924,17 @@ class ValidationController {
3662
3924
  var _a2;
3663
3925
  if (caresAboutDataChanges(new Set([binding]), weakValidation.weakBindings) && ((_a2 = weakValidation == null ? void 0 : weakValidation.get()) == null ? void 0 : _a2.severity) === "error") {
3664
3926
  weakValidation == null ? void 0 : weakValidation.weakBindings.forEach((weakBinding) => {
3665
- weakBinding === strongBinding ? newInvalidBindings.add({
3666
- binding: weakBinding,
3667
- isStrong: true
3668
- }) : newInvalidBindings.add({
3669
- binding: weakBinding,
3670
- isStrong: false
3671
- });
3927
+ if (weakBinding === strongBinding) {
3928
+ newInvalidBindings.add({
3929
+ binding: weakBinding,
3930
+ isStrong: true
3931
+ });
3932
+ } else {
3933
+ newInvalidBindings.add({
3934
+ binding: weakBinding,
3935
+ isStrong: false
3936
+ });
3937
+ }
3672
3938
  });
3673
3939
  }
3674
3940
  });
@@ -3681,6 +3947,35 @@ class ValidationController {
3681
3947
  }) })
3682
3948
  ];
3683
3949
  }
3950
+ getValidationProviders() {
3951
+ if (this.providers) {
3952
+ return this.providers;
3953
+ }
3954
+ this.providers = this.hooks.resolveValidationProviders.call([
3955
+ {
3956
+ source: SCHEMA_VALIDATION_PROVIDER_NAME,
3957
+ provider: this.schema
3958
+ },
3959
+ {
3960
+ source: VIEW_VALIDATION_PROVIDER_NAME,
3961
+ provider: {
3962
+ getValidationsForBinding: (binding) => {
3963
+ var _a, _b;
3964
+ return (_b = (_a = this.viewValidationProvider) == null ? void 0 : _a.getValidationsForBinding) == null ? void 0 : _b.call(_a, binding);
3965
+ },
3966
+ getValidationsForView: () => {
3967
+ var _a, _b;
3968
+ return (_b = (_a = this.viewValidationProvider) == null ? void 0 : _a.getValidationsForView) == null ? void 0 : _b.call(_a);
3969
+ }
3970
+ }
3971
+ }
3972
+ ]);
3973
+ return this.providers;
3974
+ }
3975
+ reset() {
3976
+ this.validations.clear();
3977
+ this.tracker = void 0;
3978
+ }
3684
3979
  onView(view) {
3685
3980
  this.validations.clear();
3686
3981
  if (!this.options) {
@@ -3689,7 +3984,7 @@ class ValidationController {
3689
3984
  const bindingTrackerPlugin = new ValidationBindingTrackerViewPlugin(__spreadProps$2(__spreadValues$3({}, this.options), {
3690
3985
  callbacks: {
3691
3986
  onAdd: (binding) => {
3692
- if (!this.options) {
3987
+ if (!this.options || this.getValidationForBinding(binding) !== void 0) {
3693
3988
  return;
3694
3989
  }
3695
3990
  const originalValue = this.options.model.get(binding);
@@ -3704,21 +3999,28 @@ class ValidationController {
3704
3999
  this.updateValidationsForBinding(binding, "load", this.options, () => {
3705
4000
  view.update(new Set([binding]));
3706
4001
  });
4002
+ this.hooks.onTrackBinding.call(binding);
3707
4003
  }
3708
4004
  }
3709
4005
  }));
3710
4006
  this.tracker = bindingTrackerPlugin;
3711
- this.providers = [this.schema, view];
4007
+ this.viewValidationProvider = view;
3712
4008
  bindingTrackerPlugin.apply(view);
3713
4009
  }
3714
- updateValidationsForBinding(binding, trigger, context, onDismiss) {
4010
+ updateValidationsForBinding(binding, trigger, validationContext, onDismiss) {
3715
4011
  var _a;
4012
+ const context = validationContext != null ? validationContext : this.options;
4013
+ if (!context) {
4014
+ throw new Error(`Context is required for executing validations`);
4015
+ }
3716
4016
  if (trigger === "load") {
3717
- const possibleValidations = this.providers.reduce((vals, provider) => {
3718
- var _a2, _b;
4017
+ const possibleValidations = this.getValidationProviders().reduce((vals, provider) => {
4018
+ var _a2, _b, _c, _d;
3719
4019
  return [
3720
4020
  ...vals,
3721
- ...(_b = (_a2 = provider.getValidationsForBinding) == null ? void 0 : _a2.call(provider, binding)) != null ? _b : []
4021
+ ...(_d = (_c = (_b = (_a2 = provider.provider).getValidationsForBinding) == null ? void 0 : _b.call(_a2, binding)) == null ? void 0 : _c.map((valObj) => __spreadProps$2(__spreadValues$3({}, valObj), {
4022
+ [VALIDATION_PROVIDER_NAME_SYMBOL]: provider.source
4023
+ }))) != null ? _d : []
3722
4024
  ];
3723
4025
  }, []);
3724
4026
  if (possibleValidations.length === 0) {
@@ -3728,7 +4030,7 @@ class ValidationController {
3728
4030
  }
3729
4031
  const trackedValidations = this.validations.get(binding);
3730
4032
  trackedValidations == null ? void 0 : trackedValidations.update(trigger, true, (validationObj) => {
3731
- const response = this.validationRunner(validationObj, context, binding);
4033
+ const response = this.validationRunner(validationObj, binding, context);
3732
4034
  if (this.weakBindingTracker.size > 0) {
3733
4035
  const t = this.validations.get(binding);
3734
4036
  this.weakBindingTracker.forEach((b) => t.weakBindings.add(b));
@@ -3739,27 +4041,33 @@ class ValidationController {
3739
4041
  this.validations.forEach((validation, vBinding) => {
3740
4042
  if (vBinding !== binding && caresAboutDataChanges(new Set([binding]), validation.weakBindings)) {
3741
4043
  validation.update(trigger, true, (validationObj) => {
3742
- const response = this.validationRunner(validationObj, context, vBinding);
4044
+ const response = this.validationRunner(validationObj, vBinding, context);
3743
4045
  return response ? { message: response.message } : void 0;
3744
4046
  });
3745
4047
  }
3746
4048
  });
3747
4049
  }
3748
4050
  }
3749
- validationRunner(validationObj, context, binding) {
3750
- const handler = this.getValidator(validationObj.type);
4051
+ validationRunner(validationObj, binding, context = this.options) {
4052
+ var _a;
4053
+ if (!context) {
4054
+ throw new Error("No context provided to validation runner");
4055
+ }
4056
+ const handler = (_a = validationObj.handler) != null ? _a : this.getValidator(validationObj.type);
3751
4057
  const weakBindings = new Set();
3752
4058
  const model = {
3753
- get(b, options = { includeInvalid: true }) {
4059
+ get(b, options) {
3754
4060
  weakBindings.add(isBinding(b) ? binding : context.parseBinding(b));
3755
- return context.model.get(b, options);
4061
+ return context.model.get(b, __spreadProps$2(__spreadValues$3({}, options), { includeInvalid: true }));
3756
4062
  },
3757
- set: context.model.set
4063
+ set: context.model.set,
4064
+ delete: context.model.delete
3758
4065
  };
3759
4066
  const result = handler == null ? void 0 : handler(__spreadProps$2(__spreadValues$3({}, context), {
3760
4067
  evaluate: (exp, options = { model }) => context.evaluate(exp, options),
3761
4068
  model,
3762
- validation: validationObj
4069
+ validation: validationObj,
4070
+ schemaType: this.schema.getType(binding)
3763
4071
  }), context.model.get(binding, {
3764
4072
  includeInvalid: true,
3765
4073
  formatted: validationObj.dataTarget === "formatted"
@@ -3783,19 +4091,25 @@ class ValidationController {
3783
4091
  }
3784
4092
  }
3785
4093
  updateValidationsForView(trigger) {
3786
- const { activeBindings } = this;
3787
- const canDismiss = trigger !== "navigation" || this.setCompare(this.lastActiveBindings, activeBindings);
3788
- this.getBindings().forEach((binding) => {
3789
- var _a;
3790
- (_a = this.validations.get(binding)) == null ? void 0 : _a.update(trigger, canDismiss, (obj) => {
3791
- if (!this.options) {
3792
- return;
3793
- }
3794
- return this.validationRunner(obj, this.options, binding);
4094
+ const isNavigationTrigger = trigger === "navigation";
4095
+ const lastActiveBindings = this.activeBindings;
4096
+ const updateValidations = (dismissValidations) => {
4097
+ this.getBindings().forEach((binding) => {
4098
+ var _a;
4099
+ (_a = this.validations.get(binding)) == null ? void 0 : _a.update(trigger, dismissValidations, (obj) => {
4100
+ if (!this.options) {
4101
+ return;
4102
+ }
4103
+ return this.validationRunner(obj, binding, this.options);
4104
+ });
3795
4105
  });
3796
- });
3797
- if (trigger === "navigation") {
3798
- this.lastActiveBindings = activeBindings;
4106
+ };
4107
+ updateValidations(!isNavigationTrigger);
4108
+ if (isNavigationTrigger) {
4109
+ const { activeBindings } = this;
4110
+ if (this.setCompare(lastActiveBindings, activeBindings)) {
4111
+ updateValidations(true);
4112
+ }
3799
4113
  }
3800
4114
  }
3801
4115
  setCompare(set1, set2) {
@@ -3825,19 +4139,30 @@ class ValidationController {
3825
4139
  var _a, _b;
3826
4140
  return (_b = (_a = this.tracker) == null ? void 0 : _a.getBindings()) != null ? _b : new Set();
3827
4141
  }
4142
+ trackBinding(binding) {
4143
+ var _a;
4144
+ (_a = this.tracker) == null ? void 0 : _a.trackBinding(binding);
4145
+ }
3828
4146
  validateView(trigger = "navigation") {
3829
4147
  this.updateValidationsForView(trigger);
3830
4148
  const validations = new Map();
4149
+ let canTransition = true;
3831
4150
  this.getBindings().forEach((b) => {
3832
- var _a, _b;
3833
- const invalid = (_a = this.getValidationForBinding(b)) == null ? void 0 : _a.get();
3834
- if (invalid) {
3835
- (_b = this.options) == null ? void 0 : _b.logger.debug(`Validation on binding: ${b.asString()} is preventing navigation. ${JSON.stringify(invalid)}`);
3836
- validations.set(b, invalid);
3837
- }
4151
+ var _a;
4152
+ const allValidations = (_a = this.getValidationForBinding(b)) == null ? void 0 : _a.getAll();
4153
+ allValidations == null ? void 0 : allValidations.forEach((v) => {
4154
+ var _a2;
4155
+ if (trigger === "navigation" && v.blocking) {
4156
+ (_a2 = this.options) == null ? void 0 : _a2.logger.debug(`Validation on binding: ${b.asString()} is preventing navigation. ${JSON.stringify(v)}`);
4157
+ canTransition = false;
4158
+ }
4159
+ if (!validations.has(b)) {
4160
+ validations.set(b, v);
4161
+ }
4162
+ });
3838
4163
  });
3839
4164
  return {
3840
- canTransition: validations.size === 0,
4165
+ canTransition,
3841
4166
  validations: validations.size ? validations : void 0
3842
4167
  };
3843
4168
  }
@@ -3847,8 +4172,7 @@ class ValidationController {
3847
4172
  forView(parser) {
3848
4173
  return {
3849
4174
  _getValidationForBinding: (binding) => {
3850
- var _a;
3851
- return (_a = this.getValidationForBinding(isBinding(binding) ? binding : parser(binding))) == null ? void 0 : _a.get();
4175
+ return this.getValidationForBinding(isBinding(binding) ? binding : parser(binding));
3852
4176
  },
3853
4177
  getAll: () => {
3854
4178
  const bindings = this.getBindings();
@@ -3868,6 +4192,9 @@ class ValidationController {
3868
4192
  get() {
3869
4193
  throw new Error("Error Access be provided by the view plugin");
3870
4194
  },
4195
+ getValidationsForBinding() {
4196
+ throw new Error("Error rollup should be provided by the view plugin");
4197
+ },
3871
4198
  getChildren() {
3872
4199
  throw new Error("Error rollup should be provided by the view plugin");
3873
4200
  },
@@ -3878,7 +4205,7 @@ class ValidationController {
3878
4205
  throw new Error("Tracking should be provided by the view plugin");
3879
4206
  },
3880
4207
  register: () => {
3881
- throw new Error("Section funcationality hould be provided by the view plugin");
4208
+ throw new Error("Section functionality should be provided by the view plugin");
3882
4209
  },
3883
4210
  type: (binding) => this.schema.getType(isBinding(binding) ? binding : parser(binding))
3884
4211
  };
@@ -3994,10 +4321,11 @@ class AssetTransformCorePlugin {
3994
4321
  };
3995
4322
  };
3996
4323
  resolver.hooks.beforeResolve.tap("asset-transform", (node, options) => {
4324
+ var _a;
3997
4325
  if (node && (node.type === "asset" || node.type === "view")) {
3998
4326
  const transform = this.registry.get(node.value);
3999
4327
  if (transform == null ? void 0 : transform.beforeResolve) {
4000
- const store = getStore(node, this.beforeResolveSymbol);
4328
+ const store = getStore((_a = options.node) != null ? _a : node, this.beforeResolveSymbol);
4001
4329
  return transform.beforeResolve(node, options, store);
4002
4330
  }
4003
4331
  }
@@ -4075,14 +4403,26 @@ class ViewController {
4075
4403
  }
4076
4404
  });
4077
4405
  });
4078
- options.model.hooks.onUpdate.tap("viewController", (updates) => {
4406
+ const update = (updates) => {
4079
4407
  if (this.currentView) {
4080
4408
  if (this.optimizeUpdates) {
4081
- this.queueUpdate(new Set(updates.map((t) => t.binding)));
4409
+ this.queueUpdate(updates);
4082
4410
  } else {
4083
4411
  this.currentView.update();
4084
4412
  }
4085
4413
  }
4414
+ };
4415
+ options.model.hooks.onUpdate.tap("viewController", (updates) => {
4416
+ update(new Set(updates.map((t) => t.binding)));
4417
+ });
4418
+ options.model.hooks.onDelete.tap("viewController", (binding) => {
4419
+ const parentBinding = binding.parent();
4420
+ const property = binding.key();
4421
+ if (typeof property === "number" && parentBinding) {
4422
+ update(new Set([parentBinding]));
4423
+ } else {
4424
+ update(new Set([binding]));
4425
+ }
4086
4426
  });
4087
4427
  }
4088
4428
  queueUpdate(bindings) {
@@ -4183,16 +4523,19 @@ class DataController {
4183
4523
  });
4184
4524
  }
4185
4525
  const setUpdates = normalizedTransaction.reduce((updates, [binding, newVal]) => {
4186
- var _a;
4526
+ var _a, _b;
4187
4527
  const oldVal = this.get(binding, { includeInvalid: true });
4188
- if (!dequal(oldVal, newVal)) {
4189
- updates.push({
4190
- binding,
4191
- newValue: newVal,
4192
- oldValue: oldVal
4193
- });
4528
+ const update = {
4529
+ binding,
4530
+ newValue: newVal,
4531
+ oldValue: oldVal
4532
+ };
4533
+ if (dequal(oldVal, newVal)) {
4534
+ (_a = this.logger) == null ? void 0 : _a.debug(`Skipping update for path: ${binding.asString()}. Value was unchanged: ${oldVal}`);
4535
+ } else {
4536
+ updates.push(update);
4537
+ (_b = this.logger) == null ? void 0 : _b.debug(`Setting path: ${binding.asString()} from: ${oldVal} to: ${newVal}`);
4194
4538
  }
4195
- (_a = this.logger) == null ? void 0 : _a.debug(`Setting path: ${binding.asString()} from: ${oldVal} to: ${newVal}`);
4196
4539
  return updates;
4197
4540
  }, []);
4198
4541
  const result = this.getModel().set(normalizedTransaction, options);
@@ -4205,17 +4548,16 @@ class DataController {
4205
4548
  }
4206
4549
  });
4207
4550
  this.hooks.onSet.call(normalizedTransaction);
4208
- this.hooks.onSet.call(normalizedTransaction);
4209
4551
  if (setUpdates.length > 0) {
4210
4552
  this.hooks.onUpdate.call(setUpdates, options);
4211
4553
  }
4212
4554
  return result;
4213
4555
  }
4214
- resolve(binding) {
4215
- return Array.isArray(binding) || typeof binding === "string" ? this.pathResolver.parse(binding) : binding;
4556
+ resolve(binding, readOnly) {
4557
+ return Array.isArray(binding) || typeof binding === "string" ? this.pathResolver.parse(binding, { readOnly }) : binding;
4216
4558
  }
4217
4559
  get(binding, options) {
4218
- const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding);
4560
+ const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding, true);
4219
4561
  let result = this.getModel().get(resolved, options);
4220
4562
  if (result === void 0 && !(options == null ? void 0 : options.ignoreDefaultValue)) {
4221
4563
  const defaultVal = this.hooks.resolveDefaultValue.call(resolved);
@@ -4225,44 +4567,26 @@ class DataController {
4225
4567
  }
4226
4568
  if (options == null ? void 0 : options.formatted) {
4227
4569
  result = this.hooks.format.call(result, resolved);
4570
+ } else if ((options == null ? void 0 : options.formatted) === false) {
4571
+ result = this.hooks.deformat.call(result, resolved);
4228
4572
  }
4229
4573
  this.hooks.onGet.call(binding, result);
4230
4574
  return result;
4231
4575
  }
4232
- delete(binding) {
4233
- if (binding === void 0 || binding === null) {
4234
- throw new Error(`Invalid arguments: delete expects a data path (string)`);
4576
+ delete(binding, options) {
4577
+ if (typeof binding !== "string" && !Array.isArray(binding) && !(binding instanceof BindingInstance)) {
4578
+ throw new Error("Invalid arguments: delete expects a data path (string)");
4235
4579
  }
4236
- const resolved = this.resolve(binding);
4237
- this.hooks.onDelete.call(resolved);
4238
- this.deleteData(resolved);
4239
- }
4240
- getTrash() {
4241
- return this.trash;
4242
- }
4243
- addToTrash(binding) {
4244
- this.trash.add(binding);
4245
- }
4246
- deleteData(binding) {
4247
- const parentBinding = binding.parent();
4248
- const parentPath = parentBinding.asString();
4249
- const property = binding.key();
4250
- const existedBeforeDelete = Object.prototype.hasOwnProperty.call(this.get(parentBinding), property);
4251
- if (property !== void 0) {
4252
- const parent = parentBinding ? this.get(parentBinding) : void 0;
4253
- if (parentPath && Array.isArray(parent)) {
4254
- if (parent.length > property) {
4255
- this.set([[parentBinding, removeAt(parent, property)]]);
4256
- }
4257
- } else if (parentPath && parent[property]) {
4258
- this.set([[parentBinding, omit(parent, property)]]);
4259
- } else if (!parentPath) {
4260
- this.getModel().reset(omit(this.get(""), property));
4261
- }
4262
- }
4263
- if (existedBeforeDelete && !this.get(binding)) {
4264
- this.addToTrash(binding);
4580
+ const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding, false);
4581
+ const parentBinding = resolved.parent();
4582
+ const property = resolved.key();
4583
+ const parentValue = this.get(parentBinding);
4584
+ const existedBeforeDelete = typeof parentValue === "object" && parentValue !== null && Object.prototype.hasOwnProperty.call(parentValue, property);
4585
+ this.getModel().delete(resolved, options);
4586
+ if (existedBeforeDelete && !this.get(resolved)) {
4587
+ this.trash.add(resolved);
4265
4588
  }
4589
+ this.hooks.onDelete.call(resolved);
4266
4590
  }
4267
4591
  serialize() {
4268
4592
  return this.hooks.serialize.call(this.get(""));
@@ -4323,10 +4647,15 @@ class ConstantsController {
4323
4647
  this.tempStore.set(namespace, new LocalModel(data));
4324
4648
  }
4325
4649
  }
4326
- clearTemporaryValues() {
4327
- this.tempStore.forEach((value) => {
4328
- value.reset();
4329
- });
4650
+ clearTemporaryValues(namespace) {
4651
+ var _a;
4652
+ if (namespace) {
4653
+ (_a = this.tempStore.get(namespace)) == null ? void 0 : _a.reset();
4654
+ } else {
4655
+ this.tempStore.forEach((value) => {
4656
+ value.reset();
4657
+ });
4658
+ }
4330
4659
  }
4331
4660
  }
4332
4661
 
@@ -4364,6 +4693,39 @@ class FlowExpPlugin {
4364
4693
  }
4365
4694
  }
4366
4695
 
4696
+ const createFormatFunction = (schema) => {
4697
+ const handler = (ctx, value, formatName) => {
4698
+ var _a, _b;
4699
+ return (_b = (_a = schema.getFormatterForType({ type: formatName })) == null ? void 0 : _a.format(value)) != null ? _b : value;
4700
+ };
4701
+ return handler;
4702
+ };
4703
+ class DefaultExpPlugin {
4704
+ constructor() {
4705
+ this.name = "flow-exp-plugin";
4706
+ }
4707
+ apply(player) {
4708
+ let formatFunction;
4709
+ player.hooks.schema.tap(this.name, (schemaController) => {
4710
+ formatFunction = createFormatFunction(schemaController);
4711
+ });
4712
+ player.hooks.expressionEvaluator.tap(this.name, (expEvaluator) => {
4713
+ if (formatFunction) {
4714
+ expEvaluator.addExpressionFunction("format", formatFunction);
4715
+ }
4716
+ expEvaluator.addExpressionFunction("log", (ctx, ...args) => {
4717
+ player.logger.info(...args);
4718
+ });
4719
+ expEvaluator.addExpressionFunction("debug", (ctx, ...args) => {
4720
+ player.logger.debug(...args);
4721
+ });
4722
+ expEvaluator.addExpressionFunction("eval", (ctx, ...args) => {
4723
+ return ctx.evaluate(...args);
4724
+ });
4725
+ });
4726
+ }
4727
+ }
4728
+
4367
4729
  const NOT_STARTED_STATE = {
4368
4730
  ref: Symbol("not-started"),
4369
4731
  status: "not-started"
@@ -4408,8 +4770,8 @@ var __async = (__this, __arguments, generator) => {
4408
4770
  step((generator = generator.apply(__this, __arguments)).next());
4409
4771
  });
4410
4772
  };
4411
- const PLAYER_VERSION = "0.4.0-next.0";
4412
- const COMMIT = "6f7a8b3424cb819dfcbe830586a92711adf130ba";
4773
+ const PLAYER_VERSION = "0.4.0-next.10";
4774
+ const COMMIT = "82270dcbee70fc05ba5b5d68e566b431ff5258ec";
4413
4775
  const _Player = class {
4414
4776
  constructor(config) {
4415
4777
  this.logger = new TapableLogger();
@@ -4430,14 +4792,15 @@ const _Player = class {
4430
4792
  resolveFlowContent: new SyncWaterfallHook()
4431
4793
  };
4432
4794
  var _a;
4433
- const initialPlugins = [];
4434
- const flowExpPlugin = new FlowExpPlugin();
4435
- initialPlugins.push(flowExpPlugin);
4436
4795
  if (config == null ? void 0 : config.logger) {
4437
4796
  this.logger.addHandler(config.logger);
4438
4797
  }
4439
4798
  this.config = config || {};
4440
- this.config.plugins = [...this.config.plugins || [], ...initialPlugins];
4799
+ this.config.plugins = [
4800
+ new DefaultExpPlugin(),
4801
+ ...this.config.plugins || [],
4802
+ new FlowExpPlugin()
4803
+ ];
4441
4804
  (_a = this.config.plugins) == null ? void 0 : _a.forEach((plugin) => {
4442
4805
  plugin.apply(this);
4443
4806
  });
@@ -4528,10 +4891,11 @@ const _Player = class {
4528
4891
  flowResultDeferred.reject(e);
4529
4892
  return true;
4530
4893
  });
4531
- function resolveStrings(val) {
4894
+ function resolveStrings(val, formatted) {
4532
4895
  return resolveDataRefs(val, {
4533
4896
  model: dataController,
4534
- evaluate: expressionEvaluator.evaluate
4897
+ evaluate: expressionEvaluator.evaluate,
4898
+ formatted
4535
4899
  });
4536
4900
  }
4537
4901
  flowController.hooks.flow.tap("player", (flow) => {
@@ -4567,23 +4931,21 @@ const _Player = class {
4567
4931
  newState = setIn(state, ["ref"], resolveStrings(state.ref));
4568
4932
  }
4569
4933
  if ("param" in state) {
4570
- newState = setIn(state, ["param"], resolveStrings(state.param));
4934
+ newState = setIn(state, ["param"], resolveStrings(state.param, false));
4571
4935
  }
4572
4936
  return newState;
4573
4937
  });
4574
4938
  flow.hooks.transition.tap("player", (_oldState, newState) => {
4575
- if (newState.value.state_type === "ACTION") {
4576
- const { exp } = newState.value;
4577
- queueMicrotask(() => {
4578
- try {
4579
- flowController == null ? void 0 : flowController.transition(String(expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(exp)));
4580
- } catch (error) {
4581
- const state = this.getState();
4582
- if (error instanceof Error && state.status === "in-progress") {
4583
- state.fail(error);
4584
- }
4585
- }
4586
- });
4939
+ if (newState.value.state_type !== "VIEW") {
4940
+ validationController.reset();
4941
+ }
4942
+ });
4943
+ flow.hooks.afterTransition.tap("player", (flowInstance) => {
4944
+ var _a;
4945
+ const value = (_a = flowInstance.currentState) == null ? void 0 : _a.value;
4946
+ if (value && value.state_type === "ACTION") {
4947
+ const { exp } = value;
4948
+ flowController == null ? void 0 : flowController.transition(String(expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(exp)));
4587
4949
  }
4588
4950
  expressionEvaluator.reset();
4589
4951
  });
@@ -4601,6 +4963,11 @@ const _Player = class {
4601
4963
  parseBinding,
4602
4964
  transition: flowController.transition,
4603
4965
  model: dataController,
4966
+ utils: {
4967
+ findPlugin: (pluginSymbol) => {
4968
+ return this.findPlugin(pluginSymbol);
4969
+ }
4970
+ },
4604
4971
  logger: this.logger,
4605
4972
  flowController,
4606
4973
  schema,
@@ -4614,23 +4981,19 @@ const _Player = class {
4614
4981
  },
4615
4982
  validation: __spreadProps(__spreadValues({}, validationController.forView(parseBinding)), {
4616
4983
  type: (b) => schema.getType(parseBinding(b))
4617
- })
4984
+ }),
4985
+ constants: this.constantsController
4618
4986
  });
4619
4987
  viewController.hooks.view.tap("player", (view) => {
4620
4988
  validationController.onView(view);
4621
4989
  this.hooks.view.call(view);
4622
4990
  });
4623
4991
  this.hooks.viewController.call(viewController);
4624
- const formatFunction = (ctx, value, formatName) => {
4625
- var _a, _b;
4626
- return (_b = (_a = schema.getFormatterForType({ type: formatName })) == null ? void 0 : _a.format(value)) != null ? _b : value;
4627
- };
4628
- expressionEvaluator.addExpressionFunction("format", formatFunction);
4629
4992
  return {
4630
4993
  start: () => {
4631
4994
  flowController.start().then((endState) => {
4632
4995
  const flowResult = {
4633
- endState: resolveStrings(endState),
4996
+ endState: resolveStrings(endState, false),
4634
4997
  data: dataController.serialize()
4635
4998
  };
4636
4999
  return flowResult;
@@ -4682,8 +5045,7 @@ const _Player = class {
4682
5045
  const endProps = {
4683
5046
  ref,
4684
5047
  status: "completed",
4685
- flow: state.flow,
4686
- dataModel: state.controllers.data.getModel()
5048
+ flow: state.flow
4687
5049
  };
4688
5050
  return maybeUpdateState(__spreadValues(__spreadValues({}, yield state.flowResult), endProps));
4689
5051
  } catch (error) {
@@ -4705,5 +5067,5 @@ Player.info = {
4705
5067
  commit: COMMIT
4706
5068
  };
4707
5069
 
4708
- export { ApplicabilityPlugin, AssetTransformCorePlugin, BindingInstance, BindingParser, Builder, ConsoleLogger, ConstantsController, DataController, DependencyMiddleware, DependencyModel, DependencyTracker, EMPTY_NODE, ExpNodeOpaqueIdentifier, ExpressionEvaluator, FlowController, FlowExpPlugin, FlowInstance, LocalModel, LocalStateStore, NOOPDataModel, NOOP_MODEL, NOT_STARTED_STATE, NodeType, NoopLogger, Parser, PipelinedDataModel, Player, ProxyLogger, ROOT_BINDING, Resolver, SIMPLE_BINDING_REGEX, SchemaController, StringResolverPlugin, SwitchPlugin, TapableLogger, TemplatePlugin, ValidationBindingTrackerViewPlugin, ValidationController, ValidationMiddleware, ValidatorRegistry, ViewController, ViewInstance, caresAboutDataChanges, constructModelForPipeline, findClosestNodeAtPosition, findInArray, findNextExp, getBindingSegments, isBinding, isExpressionNode, maybeConvertToNum, parse, resolveDataRefs, resolveDataRefsInString, resolveExpressionsInString, severities, toModel, toNodeResolveOptions, withParser, withoutContext };
5070
+ export { ApplicabilityPlugin, AssetTransformCorePlugin, BindingInstance, BindingParser, Builder, ConsoleLogger, ConstantsController, DataController, DependencyMiddleware, DependencyModel, DependencyTracker, EMPTY_NODE, ExpNodeOpaqueIdentifier, ExpressionEvaluator, FlowController, FlowExpPlugin, FlowInstance, LocalModel, LocalStateStore, NOOPDataModel, NOOP_MODEL, NOT_STARTED_STATE, NodeType, NoopLogger, Parser, PipelinedDataModel, Player, ProxyLogger, ROOT_BINDING, Resolver, SCHEMA_VALIDATION_PROVIDER_NAME, SIMPLE_BINDING_REGEX, SchemaController, StringResolverPlugin, SwitchPlugin, TapableLogger, TemplatePlugin, VALIDATION_PROVIDER_NAME_SYMBOL, VIEW_VALIDATION_PROVIDER_NAME, ValidationBindingTrackerViewPlugin, ValidationController, ValidationMiddleware, ValidatorRegistry, ViewController, ViewInstance, caresAboutDataChanges, constructModelForPipeline, findClosestNodeAtPosition, findInArray, findNextExp, getBindingSegments, isBinding, isExpressionNode, isObjectExpression, maybeConvertToNum, parse, parseExpression, removeBindingAndChildrenFromMap, resolveDataRefs, resolveDataRefsInString, resolveExpressionsInString, severities, toModel, toNodeResolveOptions, withParser, withoutContext };
4709
5071
  //# sourceMappingURL=index.esm.js.map