@player-ui/player 0.3.1-next.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/index.cjs.js +899 -336
  2. package/dist/index.d.ts +275 -93
  3. package/dist/index.esm.js +890 -334
  4. package/dist/player.dev.js +11429 -0
  5. package/dist/player.prod.js +2 -0
  6. package/package.json +16 -5
  7. package/src/binding/binding.ts +8 -0
  8. package/src/binding/index.ts +14 -4
  9. package/src/binding/resolver.ts +2 -4
  10. package/src/binding-grammar/custom/index.ts +17 -9
  11. package/src/controllers/constants/index.ts +9 -5
  12. package/src/controllers/{data.ts → data/controller.ts} +62 -61
  13. package/src/controllers/data/index.ts +1 -0
  14. package/src/controllers/data/utils.ts +42 -0
  15. package/src/controllers/flow/controller.ts +16 -12
  16. package/src/controllers/flow/flow.ts +6 -1
  17. package/src/controllers/index.ts +1 -1
  18. package/src/controllers/validation/binding-tracker.ts +42 -19
  19. package/src/controllers/validation/controller.ts +375 -148
  20. package/src/controllers/view/asset-transform.ts +4 -1
  21. package/src/controllers/view/controller.ts +20 -3
  22. package/src/data/dependency-tracker.ts +14 -0
  23. package/src/data/local-model.ts +25 -1
  24. package/src/data/model.ts +60 -8
  25. package/src/data/noop-model.ts +2 -0
  26. package/src/expressions/evaluator-functions.ts +24 -2
  27. package/src/expressions/evaluator.ts +38 -34
  28. package/src/expressions/index.ts +1 -0
  29. package/src/expressions/parser.ts +116 -44
  30. package/src/expressions/types.ts +50 -17
  31. package/src/expressions/utils.ts +143 -1
  32. package/src/player.ts +60 -46
  33. package/src/plugins/default-exp-plugin.ts +57 -0
  34. package/src/plugins/flow-exp-plugin.ts +2 -2
  35. package/src/schema/schema.ts +28 -9
  36. package/src/string-resolver/index.ts +26 -9
  37. package/src/types.ts +6 -3
  38. package/src/validator/binding-map-splice.ts +59 -0
  39. package/src/validator/index.ts +1 -0
  40. package/src/validator/types.ts +11 -3
  41. package/src/validator/validation-middleware.ts +58 -6
  42. package/src/view/parser/index.ts +51 -3
  43. package/src/view/plugins/applicability.ts +1 -1
  44. package/src/view/plugins/string-resolver.ts +35 -9
  45. package/src/view/plugins/template-plugin.ts +1 -6
  46. package/src/view/resolver/index.ts +119 -54
  47. package/src/view/resolver/types.ts +48 -7
package/dist/index.cjs.js CHANGED
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var types = require('@player-ui/types');
6
6
  var tapableTs = require('tapable-ts');
7
- var NestedError = require('nested-error-stacks');
7
+ var tsNestedError = require('ts-nested-error');
8
8
  var flatten$1 = require('arr-flatten');
9
9
  var P = require('parsimmon');
10
10
  var ebnf = require('ebnf');
@@ -17,7 +17,6 @@ var partialMatchRegistry = require('@player-ui/partial-match-registry');
17
17
 
18
18
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
19
19
 
20
- var NestedError__default = /*#__PURE__*/_interopDefaultLegacy(NestedError);
21
20
  var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten$1);
22
21
  var P__default = /*#__PURE__*/_interopDefaultLegacy(P);
23
22
  var get__default = /*#__PURE__*/_interopDefaultLegacy(get);
@@ -106,7 +105,8 @@ const isIdentifierChar = (char) => {
106
105
  return false;
107
106
  }
108
107
  const charCode = char.charCodeAt(0);
109
- return charCode >= 48 && charCode <= 57 || charCode >= 65 && charCode <= 90 || charCode >= 97 && charCode <= 122 || charCode === 95 || charCode === 45 || charCode === 64;
108
+ const matches = charCode === 32 || charCode === 34 || charCode === 39 || charCode === 40 || charCode === 41 || charCode === 42 || charCode === 46 || charCode === 61 || charCode === 91 || charCode === 93 || charCode === 96 || charCode === 123 || charCode === 125;
109
+ return !matches;
110
110
  };
111
111
  const parse$1 = (path) => {
112
112
  let index = 1;
@@ -392,7 +392,7 @@ function resolveBindingAST(bindingPathNode, options, hooks) {
392
392
  try {
393
393
  return options.convertToPath(options.getValue(nestedResolvedValue.path));
394
394
  } catch (e) {
395
- throw new NestedError__default["default"](`Unable to resolve path segment: ${nestedResolvedValue.path}`, e);
395
+ throw new tsNestedError.NestedError(`Unable to resolve path segment: ${nestedResolvedValue.path}`, e);
396
396
  }
397
397
  }
398
398
  if (node.name === "Expression") {
@@ -400,7 +400,7 @@ function resolveBindingAST(bindingPathNode, options, hooks) {
400
400
  const actualValue = options.evaluate(node.value);
401
401
  return options.convertToPath(actualValue);
402
402
  } catch (e) {
403
- throw new NestedError__default["default"](`Unable to resolve path: ${node.value}`, e);
403
+ throw new tsNestedError.NestedError(`Unable to resolve path: ${node.value}`, e);
404
404
  }
405
405
  }
406
406
  throw new Error(`Unable to resolve value for node: ${node.name}`);
@@ -470,6 +470,8 @@ var __spreadValues$d = (a, b) => {
470
470
  return a;
471
471
  };
472
472
  const SIMPLE_BINDING_REGEX = /^[\w\-@]+(\.[\w\-@]+)*$/;
473
+ const BINDING_BRACKETS_REGEX = /[\s()*=`{}'"[\]]/;
474
+ const LAZY_BINDING_REGEX = /^[^.]+(\..+)*$/;
473
475
  const DEFAULT_OPTIONS = {
474
476
  get: () => {
475
477
  throw new Error("Not Implemented");
@@ -494,7 +496,7 @@ class BindingParser {
494
496
  }
495
497
  normalizePath(path, resolveOptions) {
496
498
  var _a, _b;
497
- if (path.match(SIMPLE_BINDING_REGEX) && this.hooks.skipOptimization.call(path) !== true) {
499
+ if (!BINDING_BRACKETS_REGEX.test(path) && LAZY_BINDING_REGEX.test(path) && this.hooks.skipOptimization.call(path) !== true) {
498
500
  return { path: path.split("."), updates: void 0 };
499
501
  }
500
502
  const ast = (_a = this.parseCache[path]) != null ? _a : parse$1(path);
@@ -505,7 +507,7 @@ class BindingParser {
505
507
  try {
506
508
  return resolveBindingAST(ast.path, resolveOptions, this.hooks);
507
509
  } catch (e) {
508
- throw new NestedError__default["default"](`Cannot resolve binding: ${path}`, e);
510
+ throw new tsNestedError.NestedError(`Cannot resolve binding: ${path}`, e);
509
511
  }
510
512
  }
511
513
  getBindingForNormalizedResult(normalized) {
@@ -555,7 +557,7 @@ class BindingParser {
555
557
  updates = __spreadValues$d(__spreadValues$d({}, updates), normalized.updates);
556
558
  }
557
559
  const updateKeys = Object.keys(updates);
558
- if (updateKeys.length > 0) {
560
+ if (!options.readOnly && updateKeys.length > 0) {
559
561
  const updateTransaction = updateKeys.map((updatedBinding) => [
560
562
  this.parse(updatedBinding),
561
563
  updates[updatedBinding]
@@ -651,6 +653,10 @@ class DependencyMiddleware extends DependencyTracker {
651
653
  this.addReadDep(binding);
652
654
  return next == null ? void 0 : next.get(binding, options);
653
655
  }
656
+ delete(binding, options, next) {
657
+ this.addWriteDep(binding);
658
+ return next == null ? void 0 : next.delete(binding, options);
659
+ }
654
660
  }
655
661
  class DependencyModel extends DependencyTracker {
656
662
  constructor(rootModel) {
@@ -667,6 +673,10 @@ class DependencyModel extends DependencyTracker {
667
673
  this.addReadDep(binding);
668
674
  return this.rootModel.get(binding, options);
669
675
  }
676
+ delete(binding, options) {
677
+ this.addWriteDep(binding);
678
+ return this.rootModel.delete(binding, options);
679
+ }
670
680
  }
671
681
 
672
682
  class NOOPDataModel {
@@ -676,15 +686,18 @@ class NOOPDataModel {
676
686
  set() {
677
687
  return [];
678
688
  }
689
+ delete() {
690
+ }
679
691
  }
680
692
  const NOOP_MODEL = new NOOPDataModel();
681
693
 
682
694
  const ROOT_BINDING = new BindingInstance([]);
683
695
  function withParser(model, parseBinding) {
684
- function maybeParse(binding) {
696
+ function maybeParse(binding, readOnly) {
685
697
  const parsed = isBinding(binding) ? binding : parseBinding(binding, {
686
698
  get: model.get,
687
- set: model.set
699
+ set: model.set,
700
+ readOnly
688
701
  });
689
702
  if (!parsed) {
690
703
  throw new Error("Unable to parse binding");
@@ -693,10 +706,13 @@ function withParser(model, parseBinding) {
693
706
  }
694
707
  return {
695
708
  get(binding, options) {
696
- return model.get(maybeParse(binding), options);
709
+ return model.get(maybeParse(binding, true), options);
697
710
  },
698
711
  set(transaction, options) {
699
- return model.set(transaction.map(([key, val]) => [maybeParse(key), val]), options);
712
+ return model.set(transaction.map(([key, val]) => [maybeParse(key, false), val]), options);
713
+ },
714
+ delete(binding, options) {
715
+ return model.delete(maybeParse(binding, false), options);
700
716
  }
701
717
  };
702
718
  }
@@ -705,8 +721,27 @@ function toModel(middleware, defaultOptions, next) {
705
721
  return middleware;
706
722
  }
707
723
  return {
708
- get: (binding, options) => middleware.get(binding, options != null ? options : defaultOptions, next),
709
- set: (transaction, options) => middleware.set(transaction, options != null ? options : defaultOptions, next)
724
+ get: (binding, options) => {
725
+ const resolvedOptions = options != null ? options : defaultOptions;
726
+ if (middleware.get) {
727
+ return middleware.get(binding, resolvedOptions, next);
728
+ }
729
+ return next == null ? void 0 : next.get(binding, resolvedOptions);
730
+ },
731
+ set: (transaction, options) => {
732
+ const resolvedOptions = options != null ? options : defaultOptions;
733
+ if (middleware.set) {
734
+ return middleware.set(transaction, resolvedOptions, next);
735
+ }
736
+ return next == null ? void 0 : next.set(transaction, resolvedOptions);
737
+ },
738
+ delete: (binding, options) => {
739
+ const resolvedOptions = options != null ? options : defaultOptions;
740
+ if (middleware.delete) {
741
+ return middleware.delete(binding, resolvedOptions, next);
742
+ }
743
+ return next == null ? void 0 : next.delete(binding, resolvedOptions);
744
+ }
710
745
  };
711
746
  }
712
747
  function constructModelForPipeline(pipeline) {
@@ -714,7 +749,7 @@ function constructModelForPipeline(pipeline) {
714
749
  return NOOP_MODEL;
715
750
  }
716
751
  if (pipeline.length === 1) {
717
- return pipeline[0];
752
+ return toModel(pipeline[0]);
718
753
  }
719
754
  function createModelWithOptions(options) {
720
755
  var _a;
@@ -729,6 +764,10 @@ function constructModelForPipeline(pipeline) {
729
764
  set: (transaction, options) => {
730
765
  var _a;
731
766
  return (_a = createModelWithOptions(options)) == null ? void 0 : _a.set(transaction, options);
767
+ },
768
+ delete: (binding, options) => {
769
+ var _a;
770
+ return (_a = createModelWithOptions(options)) == null ? void 0 : _a.delete(binding, options);
732
771
  }
733
772
  };
734
773
  }
@@ -765,6 +804,9 @@ class PipelinedDataModel {
765
804
  get(binding, options) {
766
805
  return this.effectiveDataModel.get(binding, options);
767
806
  }
807
+ delete(binding, options) {
808
+ return this.effectiveDataModel.delete(binding, options);
809
+ }
768
810
  }
769
811
 
770
812
  class LocalModel {
@@ -791,11 +833,24 @@ class LocalModel {
791
833
  });
792
834
  return effectiveOperations;
793
835
  }
836
+ delete(binding) {
837
+ const parentBinding = binding.parent();
838
+ if (parentBinding) {
839
+ const parentValue = this.get(parentBinding);
840
+ if (parentValue !== void 0) {
841
+ if (Array.isArray(parentValue)) {
842
+ this.model = timm.setIn(this.model, parentBinding.asArray(), timm.removeAt(parentValue, binding.key()));
843
+ } else {
844
+ this.model = timm.setIn(this.model, parentBinding.asArray(), timm.omit(parentValue, binding.key()));
845
+ }
846
+ }
847
+ }
848
+ }
794
849
  }
795
850
 
796
851
  const ExpNodeOpaqueIdentifier = Symbol("Expression Node ID");
797
852
  function isExpressionNode(x) {
798
- return typeof x === "object" && x.__id === ExpNodeOpaqueIdentifier;
853
+ return typeof x === "object" && x !== null && !Array.isArray(x) && x.__id === ExpNodeOpaqueIdentifier;
799
854
  }
800
855
 
801
856
  const PERIOD_CODE = 46;
@@ -847,6 +902,15 @@ function throwError(message, index) {
847
902
  err.description = message;
848
903
  throw err;
849
904
  }
905
+ function createSpanningLocation(start, end) {
906
+ if (!start || !end) {
907
+ return;
908
+ }
909
+ return {
910
+ start: start.start,
911
+ end: end.end
912
+ };
913
+ }
850
914
  function getMaxKeyLen(obj) {
851
915
  let maxLen = 0;
852
916
  Object.keys(obj).forEach((key) => {
@@ -868,7 +932,7 @@ const thisStr = "this";
868
932
  function binaryPrecedence(opVal) {
869
933
  return binaryOps[opVal] || 0;
870
934
  }
871
- function createBinaryExpression(operator, left, right) {
935
+ function createBinaryExpression(operator, left, right, location) {
872
936
  let type;
873
937
  if (operator === "||" || operator === "&&") {
874
938
  type = "LogicalExpression";
@@ -884,7 +948,8 @@ function createBinaryExpression(operator, left, right) {
884
948
  type,
885
949
  operator,
886
950
  left,
887
- right
951
+ right,
952
+ location
888
953
  };
889
954
  }
890
955
  function isDecimalDigit(ch) {
@@ -899,11 +964,23 @@ function isIdentifierPart(ch) {
899
964
  function isModelRefStart(ch0, ch1) {
900
965
  return ch0 === OCURL_CODE && ch1 === OCURL_CODE;
901
966
  }
902
- function parseExpression(expr) {
967
+ function parseExpression(expr, options) {
968
+ var _a;
969
+ const strictMode = (_a = options == null ? void 0 : options.strict) != null ? _a : true;
903
970
  const charAtFunc = expr.charAt;
904
971
  const charCodeAtFunc = expr.charCodeAt;
905
972
  const { length } = expr;
906
973
  let index = 0;
974
+ const getLocation = (startChar) => {
975
+ return {
976
+ start: {
977
+ character: startChar
978
+ },
979
+ end: {
980
+ character: index
981
+ }
982
+ };
983
+ };
907
984
  function exprI(i) {
908
985
  return charAtFunc.call(expr, i);
909
986
  }
@@ -917,6 +994,7 @@ function parseExpression(expr) {
917
994
  let key;
918
995
  let value;
919
996
  let chCode;
997
+ const startCharIndex = index;
920
998
  ++index;
921
999
  while (index < length) {
922
1000
  gobbleSpaces();
@@ -962,7 +1040,8 @@ function parseExpression(expr) {
962
1040
  return {
963
1041
  __id: ExpNodeOpaqueIdentifier,
964
1042
  type: "Object",
965
- attributes
1043
+ attributes,
1044
+ location: getLocation(startCharIndex)
966
1045
  };
967
1046
  }
968
1047
  function gobbleSpaces() {
@@ -974,6 +1053,7 @@ function parseExpression(expr) {
974
1053
  function gobbleExpression() {
975
1054
  const test = gobbleBinaryExpression();
976
1055
  gobbleSpaces();
1056
+ const startCharIndex = index;
977
1057
  if (index < length && exprICode(index) === QUMARK_CODE) {
978
1058
  index++;
979
1059
  const consequent = gobbleExpression();
@@ -992,7 +1072,8 @@ function parseExpression(expr) {
992
1072
  type: "ConditionalExpression",
993
1073
  test,
994
1074
  consequent,
995
- alternate
1075
+ alternate,
1076
+ location: getLocation(startCharIndex)
996
1077
  };
997
1078
  }
998
1079
  throwError("Expected :", index);
@@ -1038,7 +1119,7 @@ function parseExpression(expr) {
1038
1119
  right = stack.pop();
1039
1120
  biop = stack.pop().value;
1040
1121
  left = stack.pop();
1041
- node = createBinaryExpression(biop, left, right);
1122
+ node = createBinaryExpression(biop, left, right, createSpanningLocation(left.location, right.location));
1042
1123
  stack.push(node);
1043
1124
  }
1044
1125
  node = gobbleToken();
@@ -1051,7 +1132,7 @@ function parseExpression(expr) {
1051
1132
  i = stack.length - 1;
1052
1133
  node = stack[i];
1053
1134
  while (i > 1) {
1054
- node = createBinaryExpression(stack[i - 1].value, stack[i - 2], node);
1135
+ node = createBinaryExpression(stack[i - 1].value, stack[i - 2], node, createSpanningLocation(stack[i - 2].location, node.location));
1055
1136
  i -= 2;
1056
1137
  }
1057
1138
  return node;
@@ -1059,6 +1140,7 @@ function parseExpression(expr) {
1059
1140
  function gobbleToken() {
1060
1141
  gobbleSpaces();
1061
1142
  const ch = exprICode(index);
1143
+ const startCharIndex = index;
1062
1144
  if (isDecimalDigit(ch) || ch === PERIOD_CODE) {
1063
1145
  return gobbleNumericLiteral();
1064
1146
  }
@@ -1087,7 +1169,8 @@ function parseExpression(expr) {
1087
1169
  type: "UnaryExpression",
1088
1170
  operator: toCheck,
1089
1171
  argument: gobbleToken(),
1090
- prefix: true
1172
+ prefix: true,
1173
+ location: getLocation(startCharIndex)
1091
1174
  };
1092
1175
  }
1093
1176
  toCheck = toCheck.substr(0, --tcLen);
@@ -1096,6 +1179,7 @@ function parseExpression(expr) {
1096
1179
  }
1097
1180
  function gobbleNumericLiteral() {
1098
1181
  let num = "";
1182
+ const startCharIndex = index;
1099
1183
  while (isDecimalDigit(exprICode(index))) {
1100
1184
  num += exprI(index++);
1101
1185
  }
@@ -1129,13 +1213,15 @@ function parseExpression(expr) {
1129
1213
  __id: ExpNodeOpaqueIdentifier,
1130
1214
  type: "Literal",
1131
1215
  value: parseFloat(num),
1132
- raw: num
1216
+ raw: num,
1217
+ location: getLocation(startCharIndex)
1133
1218
  };
1134
1219
  }
1135
1220
  function gobbleStringLiteral() {
1136
1221
  const quote = exprI(index++);
1137
1222
  let str = "";
1138
1223
  let closed = false;
1224
+ const startCharIndex = index;
1139
1225
  while (index < length) {
1140
1226
  let ch = exprI(index++);
1141
1227
  if (ch === quote) {
@@ -1175,13 +1261,15 @@ function parseExpression(expr) {
1175
1261
  __id: ExpNodeOpaqueIdentifier,
1176
1262
  type: "Literal",
1177
1263
  value: str,
1178
- raw: `${quote}${str}${quote}`
1264
+ raw: `${quote}${str}${quote}`,
1265
+ location: getLocation(startCharIndex)
1179
1266
  };
1180
1267
  }
1181
1268
  function gobbleModelRef() {
1182
1269
  let str = "";
1183
1270
  let closed = false;
1184
1271
  let openBraceCount = 1;
1272
+ const startCharIndex = index;
1185
1273
  index += 2;
1186
1274
  while (index < length) {
1187
1275
  const ch = exprI(index++);
@@ -1207,7 +1295,8 @@ function parseExpression(expr) {
1207
1295
  return {
1208
1296
  __id: ExpNodeOpaqueIdentifier,
1209
1297
  type: "ModelRef",
1210
- ref: str
1298
+ ref: str,
1299
+ location: getLocation(startCharIndex)
1211
1300
  };
1212
1301
  }
1213
1302
  function gobbleIdentifier() {
@@ -1232,19 +1321,22 @@ function parseExpression(expr) {
1232
1321
  __id: ExpNodeOpaqueIdentifier,
1233
1322
  type: "Literal",
1234
1323
  value: literals[identifier],
1235
- raw: identifier
1324
+ raw: identifier,
1325
+ location: getLocation(start)
1236
1326
  };
1237
1327
  }
1238
1328
  if (identifier === thisStr) {
1239
1329
  return {
1240
1330
  __id: ExpNodeOpaqueIdentifier,
1241
- type: "ThisExpression"
1331
+ type: "ThisExpression",
1332
+ location: getLocation(start)
1242
1333
  };
1243
1334
  }
1244
1335
  return {
1245
1336
  __id: ExpNodeOpaqueIdentifier,
1246
1337
  type: "Identifier",
1247
- name: identifier
1338
+ name: identifier,
1339
+ location: getLocation(start)
1248
1340
  };
1249
1341
  }
1250
1342
  function gobbleArguments(termination) {
@@ -1268,11 +1360,15 @@ function parseExpression(expr) {
1268
1360
  }
1269
1361
  args.push(node);
1270
1362
  }
1363
+ if (charIndex !== termination) {
1364
+ throwError(`Expected ${String.fromCharCode(termination)}`, index);
1365
+ }
1271
1366
  return args;
1272
1367
  }
1273
1368
  function gobbleVariable() {
1274
1369
  let charIndex = exprICode(index);
1275
1370
  let node = charIndex === OPAREN_CODE ? gobbleGroup() : gobbleIdentifier();
1371
+ const startCharIndex = index;
1276
1372
  gobbleSpaces();
1277
1373
  charIndex = exprICode(index);
1278
1374
  while (charIndex === PERIOD_CODE || charIndex === OBRACK_CODE || charIndex === OPAREN_CODE) {
@@ -1284,7 +1380,8 @@ function parseExpression(expr) {
1284
1380
  type: "MemberExpression",
1285
1381
  computed: false,
1286
1382
  object: node,
1287
- property: gobbleIdentifier()
1383
+ property: gobbleIdentifier(),
1384
+ location: getLocation(startCharIndex)
1288
1385
  };
1289
1386
  } else if (charIndex === OBRACK_CODE) {
1290
1387
  node = {
@@ -1292,7 +1389,8 @@ function parseExpression(expr) {
1292
1389
  type: "MemberExpression",
1293
1390
  computed: true,
1294
1391
  object: node,
1295
- property: gobbleExpression()
1392
+ property: gobbleExpression(),
1393
+ location: getLocation(startCharIndex)
1296
1394
  };
1297
1395
  gobbleSpaces();
1298
1396
  charIndex = exprICode(index);
@@ -1305,7 +1403,8 @@ function parseExpression(expr) {
1305
1403
  __id: ExpNodeOpaqueIdentifier,
1306
1404
  type: "CallExpression",
1307
1405
  args: gobbleArguments(CPAREN_CODE),
1308
- callTarget: node
1406
+ callTarget: node,
1407
+ location: getLocation(startCharIndex)
1309
1408
  };
1310
1409
  }
1311
1410
  gobbleSpaces();
@@ -1324,35 +1423,51 @@ function parseExpression(expr) {
1324
1423
  throwError("Unclosed (", index);
1325
1424
  }
1326
1425
  function gobbleArray() {
1426
+ const startCharIndex = index;
1327
1427
  index++;
1328
1428
  return {
1329
1429
  __id: ExpNodeOpaqueIdentifier,
1330
1430
  type: "ArrayExpression",
1331
- elements: gobbleArguments(CBRACK_CODE)
1431
+ elements: gobbleArguments(CBRACK_CODE),
1432
+ location: getLocation(startCharIndex)
1332
1433
  };
1333
1434
  }
1334
1435
  const nodes = [];
1335
- while (index < length) {
1336
- const chIndex = exprICode(index);
1337
- if (chIndex === SEMCOL_CODE || chIndex === COMMA_CODE) {
1338
- index++;
1339
- continue;
1436
+ try {
1437
+ while (index < length) {
1438
+ const chIndex = exprICode(index);
1439
+ if (chIndex === SEMCOL_CODE || chIndex === COMMA_CODE) {
1440
+ index++;
1441
+ continue;
1442
+ }
1443
+ const node = gobbleExpression();
1444
+ if (node) {
1445
+ nodes.push(node);
1446
+ } else if (index < length) {
1447
+ throwError(`Unexpected "${exprI(index)}"`, index);
1448
+ }
1340
1449
  }
1341
- const node = gobbleExpression();
1342
- if (node) {
1343
- nodes.push(node);
1344
- } else if (index < length) {
1345
- throwError(`Unexpected "${exprI(index)}"`, index);
1450
+ if (nodes.length === 1) {
1451
+ return nodes[0];
1346
1452
  }
1453
+ return {
1454
+ __id: ExpNodeOpaqueIdentifier,
1455
+ type: "Compound",
1456
+ body: nodes,
1457
+ location: getLocation(0)
1458
+ };
1459
+ } catch (e) {
1460
+ if (strictMode || !(e instanceof Error)) {
1461
+ throw e;
1462
+ }
1463
+ return {
1464
+ __id: ExpNodeOpaqueIdentifier,
1465
+ type: "Compound",
1466
+ body: nodes,
1467
+ location: getLocation(0),
1468
+ error: e
1469
+ };
1347
1470
  }
1348
- if (nodes.length === 1) {
1349
- return nodes[0];
1350
- }
1351
- return {
1352
- __id: ExpNodeOpaqueIdentifier,
1353
- type: "Compound",
1354
- body: nodes
1355
- };
1356
1471
  }
1357
1472
 
1358
1473
  const setDataVal = (_context, binding, value) => {
@@ -1362,16 +1477,108 @@ const getDataVal = (_context, binding) => {
1362
1477
  return _context.model.get(binding);
1363
1478
  };
1364
1479
  const deleteDataVal = (_context, binding) => {
1365
- return _context.model.set([[binding, void 0]]);
1480
+ return _context.model.delete(binding);
1366
1481
  };
1482
+ const conditional = (ctx, condition, ifTrue, ifFalse) => {
1483
+ const resolution = ctx.evaluate(condition);
1484
+ if (resolution) {
1485
+ return ctx.evaluate(ifTrue);
1486
+ }
1487
+ if (ifFalse) {
1488
+ return ctx.evaluate(ifFalse);
1489
+ }
1490
+ return null;
1491
+ };
1492
+ conditional.resolveParams = false;
1367
1493
 
1368
1494
  var DEFAULT_EXPRESSION_HANDLERS = /*#__PURE__*/Object.freeze({
1369
1495
  __proto__: null,
1370
1496
  setDataVal: setDataVal,
1371
1497
  getDataVal: getDataVal,
1372
- deleteDataVal: deleteDataVal
1498
+ deleteDataVal: deleteDataVal,
1499
+ conditional: conditional
1373
1500
  });
1374
1501
 
1502
+ function withoutContext(fn) {
1503
+ return (_context, ...args) => fn(...args);
1504
+ }
1505
+ function isInRange(position, location) {
1506
+ return position.character >= location.start.character && position.character <= location.end.character;
1507
+ }
1508
+ function findClosestNodeAtPosition(node, position) {
1509
+ var _a, _b, _c, _d, _e;
1510
+ switch (node.type) {
1511
+ case "Modification":
1512
+ case "Assignment":
1513
+ case "LogicalExpression":
1514
+ case "BinaryExpression": {
1515
+ const check = (_a = findClosestNodeAtPosition(node.left, position)) != null ? _a : findClosestNodeAtPosition(node.right, position);
1516
+ if (check) {
1517
+ return check;
1518
+ }
1519
+ break;
1520
+ }
1521
+ case "UnaryExpression": {
1522
+ const checkArg = findClosestNodeAtPosition(node.argument, position);
1523
+ if (checkArg) {
1524
+ return checkArg;
1525
+ }
1526
+ break;
1527
+ }
1528
+ case "MemberExpression": {
1529
+ const checkObject = (_b = findClosestNodeAtPosition(node.object, position)) != null ? _b : findClosestNodeAtPosition(node.property, position);
1530
+ if (checkObject) {
1531
+ return checkObject;
1532
+ }
1533
+ break;
1534
+ }
1535
+ case "ConditionalExpression": {
1536
+ const checkObject = (_d = (_c = findClosestNodeAtPosition(node.test, position)) != null ? _c : findClosestNodeAtPosition(node.consequent, position)) != null ? _d : findClosestNodeAtPosition(node.alternate, position);
1537
+ if (checkObject) {
1538
+ return checkObject;
1539
+ }
1540
+ break;
1541
+ }
1542
+ case "ArrayExpression":
1543
+ case "Compound": {
1544
+ const elements = node.type === "ArrayExpression" ? node.elements : node.body;
1545
+ const anyElements = elements.find((e) => findClosestNodeAtPosition(e, position));
1546
+ if (anyElements) {
1547
+ return anyElements;
1548
+ }
1549
+ break;
1550
+ }
1551
+ case "Object": {
1552
+ const checkObject = node.attributes.reduce((found, next) => {
1553
+ var _a2;
1554
+ return (_a2 = found != null ? found : findClosestNodeAtPosition(next.key, position)) != null ? _a2 : findClosestNodeAtPosition(next.value, position);
1555
+ }, void 0);
1556
+ if (checkObject) {
1557
+ return checkObject;
1558
+ }
1559
+ break;
1560
+ }
1561
+ case "CallExpression": {
1562
+ const anyArgs = (_e = node.args.find((arg) => {
1563
+ return findClosestNodeAtPosition(arg, position);
1564
+ })) != null ? _e : findClosestNodeAtPosition(node.callTarget, position);
1565
+ if (anyArgs) {
1566
+ return anyArgs;
1567
+ }
1568
+ break;
1569
+ }
1570
+ }
1571
+ if (node.location && isInRange(position, node.location)) {
1572
+ return node;
1573
+ }
1574
+ }
1575
+ function isObjectExpression(expr) {
1576
+ if (isExpressionNode(expr)) {
1577
+ return false;
1578
+ }
1579
+ return typeof expr === "object" && expr !== null && !Array.isArray(expr) && "value" in expr;
1580
+ }
1581
+
1375
1582
  var __defProp$c = Object.defineProperty;
1376
1583
  var __defProps$a = Object.defineProperties;
1377
1584
  var __getOwnPropDescs$a = Object.getOwnPropertyDescriptors;
@@ -1432,6 +1639,8 @@ class ExpressionEvaluator {
1432
1639
  this.vars = {};
1433
1640
  this.hooks = {
1434
1641
  resolve: new tapableTs.SyncWaterfallHook(),
1642
+ resolveOptions: new tapableTs.SyncWaterfallHook(),
1643
+ beforeEvaluate: new tapableTs.SyncWaterfallHook(),
1435
1644
  onError: new tapableTs.SyncBailHook()
1436
1645
  };
1437
1646
  this.expressionsCache = new Map();
@@ -1450,21 +1659,25 @@ class ExpressionEvaluator {
1450
1659
  reset() {
1451
1660
  this.expressionsCache.clear();
1452
1661
  }
1453
- evaluate(expression, options) {
1454
- const opts = __spreadProps$a(__spreadValues$c(__spreadValues$c({}, this.defaultHookOptions), options), {
1455
- resolveNode: (node) => this._execAST(node, opts)
1456
- });
1662
+ evaluate(expr, options) {
1663
+ var _a;
1664
+ const resolvedOpts = this.hooks.resolveOptions.call(__spreadProps$a(__spreadValues$c(__spreadValues$c({}, this.defaultHookOptions), options), {
1665
+ resolveNode: (node) => this._execAST(node, resolvedOpts)
1666
+ }));
1667
+ let expression = (_a = this.hooks.beforeEvaluate.call(expr, resolvedOpts)) != null ? _a : expr;
1668
+ while (isObjectExpression(expression)) {
1669
+ expression = expression.value;
1670
+ }
1457
1671
  if (typeof expression === "number" || typeof expression === "boolean" || expression === void 0 || expression === null) {
1458
1672
  return expression;
1459
1673
  }
1460
1674
  if (isExpressionNode(expression)) {
1461
- return this._execAST(expression, opts);
1675
+ return this._execAST(expression, resolvedOpts);
1462
1676
  }
1463
- if (typeof expression === "object") {
1464
- const values = Array.isArray(expression) ? expression : Object.values(expression);
1465
- return values.reduce((_nothing, exp) => this.evaluate(exp, options), null);
1677
+ if (Array.isArray(expression)) {
1678
+ return expression.reduce((_nothing, exp) => this.evaluate(exp, options), null);
1466
1679
  }
1467
- return this._execString(String(expression), opts);
1680
+ return this._execString(String(expression), resolvedOpts);
1468
1681
  }
1469
1682
  addExpressionFunction(name, handler) {
1470
1683
  this.operators.expressions.set(name, handler);
@@ -1502,7 +1715,7 @@ class ExpressionEvaluator {
1502
1715
  this.expressionsCache.set(matchedExp, expAST);
1503
1716
  return this._execAST(expAST, options);
1504
1717
  } catch (e) {
1505
- if (!this.hooks.onError.call(e)) {
1718
+ if (options.throwErrors || !this.hooks.onError.call(e)) {
1506
1719
  throw e;
1507
1720
  }
1508
1721
  }
@@ -1556,25 +1769,18 @@ class ExpressionEvaluator {
1556
1769
  }
1557
1770
  if (node.type === "CallExpression") {
1558
1771
  const expressionName = node.callTarget.name;
1559
- if (expressionName === "conditional") {
1560
- const condition = resolveNode(node.args[0]);
1561
- if (condition) {
1562
- return resolveNode(node.args[1]);
1563
- }
1564
- if (node.args[2]) {
1565
- return resolveNode(node.args[2]);
1566
- }
1567
- return null;
1568
- }
1569
1772
  const operator = this.operators.expressions.get(expressionName);
1570
1773
  if (!operator) {
1571
1774
  throw new Error(`Unknown expression function: ${expressionName}`);
1572
1775
  }
1776
+ if ("resolveParams" in operator && operator.resolveParams === false) {
1777
+ return operator(expressionContext, ...node.args);
1778
+ }
1573
1779
  const args = node.args.map((n) => resolveNode(n));
1574
1780
  return operator(expressionContext, ...args);
1575
1781
  }
1576
1782
  if (node.type === "ModelRef") {
1577
- return model.get(node.ref);
1783
+ return model.get(node.ref, { context: { model: options.model } });
1578
1784
  }
1579
1785
  if (node.type === "MemberExpression") {
1580
1786
  const obj = resolveNode(node.object);
@@ -1626,10 +1832,6 @@ class ExpressionEvaluator {
1626
1832
  }
1627
1833
  }
1628
1834
 
1629
- function withoutContext(fn) {
1630
- return (_context, ...args) => fn(...args);
1631
- }
1632
-
1633
1835
  const severities = ["trace", "debug", "info", "warn", "error"];
1634
1836
 
1635
1837
  class ConsoleLogger {
@@ -1786,6 +1988,9 @@ function parse(schema) {
1786
1988
  if (type.isArray) {
1787
1989
  nestedPath.push("[]");
1788
1990
  }
1991
+ if (type.isRecord) {
1992
+ nestedPath.push("{}");
1993
+ }
1789
1994
  if (type.type && schema[type.type]) {
1790
1995
  parseQueue.push({
1791
1996
  path: nestedPath,
@@ -1834,8 +2039,20 @@ class SchemaController {
1834
2039
  if (cached) {
1835
2040
  return cached;
1836
2041
  }
1837
- const normalized = binding.asArray().map((p) => typeof p === "number" ? "[]" : p).join(".");
1838
- this.bindingSchemaNormalizedCache.set(binding, normalized);
2042
+ let bindingArray = binding.asArray();
2043
+ let normalized = bindingArray.map((p) => typeof p === "number" ? "[]" : p).join(".");
2044
+ if (normalized) {
2045
+ this.bindingSchemaNormalizedCache.set(binding, normalized);
2046
+ bindingArray = normalized.split(".");
2047
+ }
2048
+ bindingArray.forEach((item) => {
2049
+ const recordBinding = bindingArray.map((p) => p === item ? "{}" : p).join(".");
2050
+ if (this.schema.get(recordBinding)) {
2051
+ this.bindingSchemaNormalizedCache.set(binding, recordBinding);
2052
+ bindingArray = recordBinding.split(".");
2053
+ normalized = recordBinding;
2054
+ }
2055
+ });
1839
2056
  return normalized;
1840
2057
  }
1841
2058
  getType(binding) {
@@ -1922,6 +2139,9 @@ function findNextExp(str) {
1922
2139
  };
1923
2140
  }
1924
2141
  function resolveExpressionsInString(val, { evaluate }) {
2142
+ if (!evaluate) {
2143
+ return val;
2144
+ }
1925
2145
  const expMatch = /@\[.*?\]@/;
1926
2146
  let newVal = val;
1927
2147
  let match = newVal.match(expMatch);
@@ -1939,9 +2159,9 @@ function resolveExpressionsInString(val, { evaluate }) {
1939
2159
  return newVal;
1940
2160
  }
1941
2161
  function resolveDataRefsInString(val, options) {
1942
- const { model } = options;
2162
+ const { model, formatted = true } = options;
1943
2163
  let workingString = resolveExpressionsInString(val, options);
1944
- if (typeof workingString !== "string" || workingString.indexOf(DOUBLE_OPEN_CURLY) === -1) {
2164
+ if (!model || typeof workingString !== "string" || workingString.indexOf(DOUBLE_OPEN_CURLY) === -1) {
1945
2165
  return workingString;
1946
2166
  }
1947
2167
  while (workingString.indexOf(DOUBLE_OPEN_CURLY) !== -1) {
@@ -1951,7 +2171,7 @@ function resolveDataRefsInString(val, options) {
1951
2171
  }
1952
2172
  const { start, end } = expLocation;
1953
2173
  const binding = workingString.substring(start + DOUBLE_OPEN_CURLY.length, end - DOUBLE_OPEN_CURLY.length).trim();
1954
- const evaledVal = model.get(binding, { formatted: true });
2174
+ const evaledVal = model.get(binding, { formatted });
1955
2175
  if (start === 0 && end === workingString.length && typeof evaledVal !== "string") {
1956
2176
  return evaledVal;
1957
2177
  }
@@ -1965,12 +2185,14 @@ function traverseObject(val, options) {
1965
2185
  return resolveDataRefsInString(val, options);
1966
2186
  }
1967
2187
  case "object": {
2188
+ if (!val)
2189
+ return val;
1968
2190
  const keys = Object.keys(val);
1969
2191
  let newVal = val;
1970
2192
  if (keys.length > 0) {
1971
- for (const key of keys) {
2193
+ keys.forEach((key) => {
1972
2194
  newVal = timm.setIn(newVal, [key], traverseObject(val[key], options));
1973
- }
2195
+ });
1974
2196
  }
1975
2197
  return newVal;
1976
2198
  }
@@ -1982,6 +2204,36 @@ function resolveDataRefs(val, options) {
1982
2204
  return traverseObject(val, options);
1983
2205
  }
1984
2206
 
2207
+ function removeBindingAndChildrenFromMap(sourceMap, binding) {
2208
+ const targetMap = new Map(sourceMap);
2209
+ const parentBinding = binding.parent();
2210
+ const property = binding.key();
2211
+ targetMap.forEach((_value, trackedBinding) => {
2212
+ if (binding === trackedBinding || binding.contains(trackedBinding)) {
2213
+ targetMap.delete(trackedBinding);
2214
+ }
2215
+ });
2216
+ if (typeof property === "number") {
2217
+ const bindingsToRewrite = Array.from(sourceMap.keys()).filter((b) => {
2218
+ if (parentBinding.contains(b)) {
2219
+ const [childIndex] = b.relative(parentBinding);
2220
+ return typeof childIndex === "number" && childIndex > property;
2221
+ }
2222
+ return false;
2223
+ }).sort();
2224
+ bindingsToRewrite.forEach((trackedBinding) => {
2225
+ const [childIndex, ...childPath] = trackedBinding.relative(parentBinding);
2226
+ if (typeof childIndex === "number") {
2227
+ const newSegments = [childIndex - 1, ...childPath];
2228
+ const newChildBinding = parentBinding.descendent(newSegments);
2229
+ targetMap.set(newChildBinding, targetMap.get(trackedBinding));
2230
+ targetMap.delete(trackedBinding);
2231
+ }
2232
+ });
2233
+ }
2234
+ return targetMap;
2235
+ }
2236
+
1985
2237
  var __defProp$a = Object.defineProperty;
1986
2238
  var __defProps$8 = Object.defineProperties;
1987
2239
  var __getOwnPropDescs$8 = Object.getOwnPropertyDescriptors;
@@ -2006,12 +2258,15 @@ class ValidationMiddleware {
2006
2258
  this.validator = validator;
2007
2259
  this.shadowModelPaths = new Map();
2008
2260
  this.logger = options == null ? void 0 : options.logger;
2261
+ this.shouldIncludeInvalid = options == null ? void 0 : options.shouldIncludeInvalid;
2009
2262
  }
2010
2263
  set(transaction, options, next) {
2011
2264
  const asModel = toModel(this, __spreadProps$8(__spreadValues$a({}, options), { includeInvalid: true }), next);
2012
2265
  const nextTransaction = [];
2266
+ const includedBindings = new Set();
2013
2267
  transaction.forEach(([binding, value]) => {
2014
2268
  this.shadowModelPaths.set(binding, value);
2269
+ includedBindings.add(binding);
2015
2270
  });
2016
2271
  const invalidBindings = [];
2017
2272
  this.shadowModelPaths.forEach((value, binding) => {
@@ -2020,16 +2275,27 @@ class ValidationMiddleware {
2020
2275
  if (validations === void 0) {
2021
2276
  nextTransaction.push([binding, value]);
2022
2277
  } else if (validations instanceof Set) {
2023
- invalidBindings.push(...validations);
2024
- } else {
2278
+ validations.forEach((validation) => {
2279
+ invalidBindings.push(validation.binding);
2280
+ if (!validation.isStrong && validation.binding.asString() === binding.asString()) {
2281
+ nextTransaction.push([validation.binding, value]);
2282
+ }
2283
+ });
2284
+ } else if (includedBindings.has(binding)) {
2285
+ invalidBindings.push(binding);
2025
2286
  (_a = this.logger) == null ? void 0 : _a.debug(`Invalid value for path: ${binding.asString()} - ${validations.severity} - ${validations.message}`);
2026
2287
  }
2027
2288
  });
2289
+ let validResults = [];
2028
2290
  if (next && nextTransaction.length > 0) {
2029
2291
  nextTransaction.forEach(([binding]) => this.shadowModelPaths.delete(binding));
2030
- return next.set(nextTransaction, options);
2292
+ const result = next.set(nextTransaction, options);
2293
+ if (invalidBindings.length === 0) {
2294
+ return result;
2295
+ }
2296
+ validResults = result;
2031
2297
  }
2032
- return invalidBindings.map((binding) => {
2298
+ const invalidResults = invalidBindings.map((binding) => {
2033
2299
  return {
2034
2300
  binding,
2035
2301
  oldValue: asModel.get(binding),
@@ -2037,10 +2303,12 @@ class ValidationMiddleware {
2037
2303
  force: true
2038
2304
  };
2039
2305
  });
2306
+ return [...validResults, ...invalidResults];
2040
2307
  }
2041
2308
  get(binding, options, next) {
2309
+ var _a, _b;
2042
2310
  let val = next == null ? void 0 : next.get(binding, options);
2043
- if ((options == null ? void 0 : options.includeInvalid) === true) {
2311
+ if ((_b = (_a = this.shouldIncludeInvalid) == null ? void 0 : _a.call(this, options)) != null ? _b : (options == null ? void 0 : options.includeInvalid) === true) {
2044
2312
  this.shadowModelPaths.forEach((shadowValue, shadowBinding) => {
2045
2313
  if (shadowBinding === binding) {
2046
2314
  val = shadowValue;
@@ -2053,6 +2321,10 @@ class ValidationMiddleware {
2053
2321
  }
2054
2322
  return val;
2055
2323
  }
2324
+ delete(binding, options, next) {
2325
+ this.shadowModelPaths = removeBindingAndChildrenFromMap(this.shadowModelPaths, binding);
2326
+ return next == null ? void 0 : next.delete(binding, options);
2327
+ }
2056
2328
  }
2057
2329
 
2058
2330
  class ValidatorRegistry {
@@ -2137,6 +2409,9 @@ class Parser {
2137
2409
  }
2138
2410
  return tapped;
2139
2411
  }
2412
+ hasTemplateValues(obj, localKey) {
2413
+ return Object.hasOwnProperty.call(obj, "template") && Array.isArray(obj == null ? void 0 : obj.template) && obj.template.length && obj.template.find((tmpl) => tmpl.output === localKey);
2414
+ }
2140
2415
  parseObject(obj, type = exports.NodeType.Value, options = { templateDepth: 0 }) {
2141
2416
  var _a;
2142
2417
  const nodeType = this.hooks.determineNodeType.call(obj);
@@ -2154,12 +2429,19 @@ class Parser {
2154
2429
  if (!localObj) {
2155
2430
  return currentValue;
2156
2431
  }
2157
- const objEntries = Array.isArray(localObj) ? localObj.map((v, i) => [i, v]) : Object.entries(localObj);
2432
+ const objEntries = Array.isArray(localObj) ? localObj.map((v, i) => [i, v]) : [
2433
+ ...Object.entries(localObj),
2434
+ ...Object.getOwnPropertySymbols(localObj).map((s) => [
2435
+ s,
2436
+ localObj[s]
2437
+ ])
2438
+ ];
2158
2439
  const defaultValue = {
2159
2440
  children: [],
2160
2441
  value: currentValue
2161
2442
  };
2162
2443
  const newValue = objEntries.reduce((accumulation, current) => {
2444
+ var _b;
2163
2445
  const _a2 = accumulation, { children: children2 } = _a2, rest = __objRest$1(_a2, ["children"]);
2164
2446
  const [localKey, localValue] = current;
2165
2447
  if (localKey === "asset" && typeof localValue === "object") {
@@ -2177,14 +2459,19 @@ class Parser {
2177
2459
  }
2178
2460
  } else if (this.hooks.determineNodeType.call(localKey) === exports.NodeType.Template && Array.isArray(localValue)) {
2179
2461
  const templateChildren = localValue.map((template) => {
2180
- var _a3, _b;
2462
+ var _a3, _b2;
2181
2463
  const templateAST = this.hooks.onCreateASTNode.call({
2182
2464
  type: exports.NodeType.Template,
2183
2465
  depth: (_a3 = options.templateDepth) != null ? _a3 : 0,
2184
2466
  data: template.data,
2185
2467
  template: template.value,
2186
- dynamic: (_b = template.dynamic) != null ? _b : false
2468
+ dynamic: (_b2 = template.dynamic) != null ? _b2 : false
2187
2469
  }, template);
2470
+ if ((templateAST == null ? void 0 : templateAST.type) === exports.NodeType.MultiNode) {
2471
+ templateAST.values.forEach((v) => {
2472
+ v.parent = templateAST;
2473
+ });
2474
+ }
2188
2475
  if (templateAST) {
2189
2476
  return {
2190
2477
  path: [...path, template.output],
@@ -2198,6 +2485,18 @@ class Parser {
2198
2485
  });
2199
2486
  } else if (localValue && this.hooks.determineNodeType.call(localValue) === exports.NodeType.Switch) {
2200
2487
  const localSwitch = this.hooks.parseNode.call(localValue, exports.NodeType.Value, options, exports.NodeType.Switch);
2488
+ if (localSwitch && localSwitch.type === exports.NodeType.Value && ((_b = localSwitch.children) == null ? void 0 : _b.length) === 1 && localSwitch.value === void 0) {
2489
+ const firstChild = localSwitch.children[0];
2490
+ return __spreadProps$7(__spreadValues$9({}, rest), {
2491
+ children: [
2492
+ ...children2,
2493
+ {
2494
+ path: [...path, localKey, ...firstChild.path],
2495
+ value: firstChild.value
2496
+ }
2497
+ ]
2498
+ });
2499
+ }
2201
2500
  if (localSwitch) {
2202
2501
  return __spreadProps$7(__spreadValues$9({}, rest), {
2203
2502
  children: [
@@ -2214,7 +2513,7 @@ class Parser {
2214
2513
  if (childValues.length > 0) {
2215
2514
  const multiNode = this.hooks.onCreateASTNode.call({
2216
2515
  type: exports.NodeType.MultiNode,
2217
- override: true,
2516
+ override: !this.hasTemplateValues(localObj, localKey),
2218
2517
  values: childValues
2219
2518
  }, localValue);
2220
2519
  if ((multiNode == null ? void 0 : multiNode.type) === exports.NodeType.MultiNode) {
@@ -2237,7 +2536,7 @@ class Parser {
2237
2536
  } else if (localValue && typeof localValue === "object") {
2238
2537
  const determineNodeType = this.hooks.determineNodeType.call(localValue);
2239
2538
  if (determineNodeType === exports.NodeType.Applicability) {
2240
- const parsedNode = this.hooks.parseNode.call(localValue, type, options, determineNodeType);
2539
+ const parsedNode = this.hooks.parseNode.call(localValue, exports.NodeType.Value, options, determineNodeType);
2241
2540
  if (parsedNode) {
2242
2541
  return __spreadProps$7(__spreadValues$9({}, rest), {
2243
2542
  children: [
@@ -2359,6 +2658,11 @@ const withContext = (model) => {
2359
2658
  return model.set(transaction, __spreadValues$7({
2360
2659
  context: { model }
2361
2660
  }, options));
2661
+ },
2662
+ delete: (binding, options) => {
2663
+ return model.delete(binding, __spreadValues$7({
2664
+ context: { model }
2665
+ }, options));
2362
2666
  }
2363
2667
  };
2364
2668
  };
@@ -2388,12 +2692,16 @@ class Resolver {
2388
2692
  this.hooks.beforeUpdate.call(changes);
2389
2693
  const resolveCache = new Map();
2390
2694
  this.idCache.clear();
2695
+ const prevASTMap = new Map(this.ASTMap);
2391
2696
  this.ASTMap.clear();
2392
- const updated = this.computeTree(this.root, void 0, changes, resolveCache, toNodeResolveOptions(this.options));
2697
+ const updated = this.computeTree(this.root, void 0, changes, resolveCache, toNodeResolveOptions(this.options), void 0, prevASTMap);
2393
2698
  this.resolveCache = resolveCache;
2394
2699
  this.hooks.afterUpdate.call(updated.value);
2395
2700
  return updated.value;
2396
2701
  }
2702
+ getResolveCache() {
2703
+ return new Map(this.resolveCache);
2704
+ }
2397
2705
  getNodeID(node) {
2398
2706
  var _a;
2399
2707
  if (!node) {
@@ -2425,7 +2733,19 @@ class Resolver {
2425
2733
  }
2426
2734
  return this.resolveCache.get(node);
2427
2735
  }
2428
- computeTree(node, parent, dataChanges, cacheUpdate, options) {
2736
+ cloneNode(node) {
2737
+ const clonedNode = timm.clone(node);
2738
+ Object.keys(clonedNode).forEach((key) => {
2739
+ if (key === "parent")
2740
+ return;
2741
+ const value = clonedNode[key];
2742
+ if (typeof value === "object" && value !== null) {
2743
+ clonedNode[key] = Array.isArray(value) ? [...value] : __spreadValues$7({}, value);
2744
+ }
2745
+ });
2746
+ return clonedNode;
2747
+ }
2748
+ computeTree(node, parent, dataChanges, cacheUpdate, options, parentNode, prevASTMap) {
2429
2749
  var _a, _b;
2430
2750
  const dependencyModel = new DependencyModel(options.data.model);
2431
2751
  dependencyModel.trackSubset("core");
@@ -2446,34 +2766,40 @@ class Resolver {
2446
2766
  updated: false
2447
2767
  });
2448
2768
  cacheUpdate.set(node, update2);
2449
- const repopulateASTMapFromCache = (resolvedAST3, AST) => {
2769
+ const repopulateASTMapFromCache = (resolvedNode, AST, ASTParent) => {
2450
2770
  var _a2;
2451
- this.ASTMap.set(resolvedAST3, AST);
2452
- if ("children" in resolvedAST3) {
2453
- (_a2 = resolvedAST3.children) == null ? void 0 : _a2.forEach(({ value: childAST }) => {
2454
- const { node: childResolvedAST } = this.getPreviousResult(childAST) || {};
2455
- if (!childResolvedAST)
2456
- return;
2457
- repopulateASTMapFromCache(childResolvedAST, childAST);
2458
- if (childResolvedAST.type === exports.NodeType.MultiNode) {
2459
- childResolvedAST.values.forEach((mChildAST) => {
2460
- const { node: mChildResolvedAST } = this.getPreviousResult(mChildAST) || {};
2461
- if (!mChildResolvedAST)
2462
- return;
2463
- repopulateASTMapFromCache(mChildResolvedAST, mChildAST);
2464
- });
2465
- }
2466
- });
2771
+ const { node: resolvedAST2 } = resolvedNode;
2772
+ this.ASTMap.set(resolvedAST2, AST);
2773
+ const resolvedUpdate = __spreadProps$5(__spreadValues$7({}, resolvedNode), {
2774
+ updated: false
2775
+ });
2776
+ cacheUpdate.set(AST, resolvedUpdate);
2777
+ const handleChildNode = (childNode) => {
2778
+ var _a3;
2779
+ const originalChildNode = (_a3 = prevASTMap.get(childNode)) != null ? _a3 : childNode;
2780
+ const previousChildResult = this.getPreviousResult(originalChildNode);
2781
+ if (!previousChildResult)
2782
+ return;
2783
+ repopulateASTMapFromCache(previousChildResult, originalChildNode, AST);
2784
+ };
2785
+ if ("children" in resolvedAST2) {
2786
+ (_a2 = resolvedAST2.children) == null ? void 0 : _a2.forEach(({ value: childAST }) => handleChildNode(childAST));
2787
+ } else if (resolvedAST2.type === exports.NodeType.MultiNode) {
2788
+ resolvedAST2.values.forEach(handleChildNode);
2467
2789
  }
2790
+ this.hooks.afterNodeUpdate.call(AST, ASTParent, resolvedUpdate);
2468
2791
  };
2469
- const resolvedAST2 = previousResult.node;
2470
- repopulateASTMapFromCache(resolvedAST2, node);
2471
- this.hooks.afterNodeUpdate.call(node, parent, update2);
2792
+ previousResult.node.parent = parentNode;
2793
+ repopulateASTMapFromCache(previousResult, node, parent);
2472
2794
  return update2;
2473
2795
  }
2474
- const resolvedAST = (_a = this.hooks.beforeResolve.call(node, resolveOptions)) != null ? _a : {
2796
+ const clonedNode = __spreadProps$5(__spreadValues$7({}, this.cloneNode(node)), {
2797
+ parent: parentNode
2798
+ });
2799
+ const resolvedAST = (_a = this.hooks.beforeResolve.call(clonedNode, resolveOptions)) != null ? _a : {
2475
2800
  type: exports.NodeType.Empty
2476
2801
  };
2802
+ resolvedAST.parent = parentNode;
2477
2803
  resolveOptions.node = resolvedAST;
2478
2804
  this.ASTMap.set(resolvedAST, node);
2479
2805
  let resolved = this.hooks.resolve.call(void 0, resolvedAST, resolveOptions);
@@ -2484,22 +2810,15 @@ class Resolver {
2484
2810
  const childDependencies = new Set();
2485
2811
  dependencyModel.trackSubset("children");
2486
2812
  if ("children" in resolvedAST) {
2487
- (_b = resolvedAST.children) == null ? void 0 : _b.forEach((child) => {
2488
- const computedChildTree = this.computeTree(child.value, node, dataChanges, cacheUpdate, resolveOptions);
2489
- let { updated: childUpdated, value: childValue } = computedChildTree;
2490
- const { node: childNode, dependencies: childTreeDeps } = computedChildTree;
2813
+ const newChildren = (_b = resolvedAST.children) == null ? void 0 : _b.map((child) => {
2814
+ const computedChildTree = this.computeTree(child.value, node, dataChanges, cacheUpdate, resolveOptions, resolvedAST, prevASTMap);
2815
+ const {
2816
+ dependencies: childTreeDeps,
2817
+ node: childNode,
2818
+ updated: childUpdated,
2819
+ value: childValue
2820
+ } = computedChildTree;
2491
2821
  childTreeDeps.forEach((binding) => childDependencies.add(binding));
2492
- if (childNode.type === exports.NodeType.MultiNode) {
2493
- childValue = [];
2494
- childNode.values.forEach((mValue) => {
2495
- const mTree = this.computeTree(mValue, node, dataChanges, cacheUpdate, resolveOptions);
2496
- if (mTree.value !== void 0 && mTree.value !== null) {
2497
- childValue.push(mTree.value);
2498
- }
2499
- mTree.dependencies.forEach((bindingDep) => childDependencies.add(bindingDep));
2500
- childUpdated = childUpdated || mTree.updated;
2501
- });
2502
- }
2503
2822
  if (childValue) {
2504
2823
  if (childNode.type === exports.NodeType.MultiNode && !childNode.override) {
2505
2824
  const arr = timm.addLast(get__default["default"](resolved, child.path, []), childValue);
@@ -2509,7 +2828,22 @@ class Resolver {
2509
2828
  }
2510
2829
  }
2511
2830
  updated = updated || childUpdated;
2831
+ return __spreadProps$5(__spreadValues$7({}, child), { value: childNode });
2512
2832
  });
2833
+ resolvedAST.children = newChildren;
2834
+ } else if (resolvedAST.type === exports.NodeType.MultiNode) {
2835
+ const childValue = [];
2836
+ const newValues = resolvedAST.values.map((mValue) => {
2837
+ const mTree = this.computeTree(mValue, node, dataChanges, cacheUpdate, resolveOptions, resolvedAST, prevASTMap);
2838
+ if (mTree.value !== void 0 && mTree.value !== null) {
2839
+ childValue.push(mTree.value);
2840
+ }
2841
+ mTree.dependencies.forEach((bindingDep) => childDependencies.add(bindingDep));
2842
+ updated = updated || mTree.updated;
2843
+ return mTree.node;
2844
+ });
2845
+ resolvedAST.values = newValues;
2846
+ resolved = childValue;
2513
2847
  }
2514
2848
  childDependencies.forEach((bindingDep) => dependencyModel.addChildReadDep(bindingDep));
2515
2849
  dependencyModel.trackSubset("core");
@@ -2578,13 +2912,10 @@ class TemplatePlugin {
2578
2912
  }
2579
2913
  });
2580
2914
  const result = {
2581
- parent: node.parent,
2582
2915
  type: exports.NodeType.MultiNode,
2916
+ override: false,
2583
2917
  values
2584
2918
  };
2585
- result.values.forEach((innerNode) => {
2586
- innerNode.parent = result;
2587
- });
2588
2919
  return result;
2589
2920
  }
2590
2921
  applyParser(parser) {
@@ -2678,30 +3009,44 @@ function resolveAllRefs(node, resolveOptions, propertiesToSkip) {
2678
3009
  });
2679
3010
  return newNode;
2680
3011
  }
2681
- const findBasePath = (node) => {
3012
+ const findBasePath = (node, resolver) => {
2682
3013
  var _a, _b, _c;
2683
3014
  const parentNode = node.parent;
2684
3015
  if (!parentNode) {
2685
3016
  return [];
2686
3017
  }
2687
3018
  if ("children" in parentNode) {
2688
- return (_c = (_b = (_a = parentNode.children) == null ? void 0 : _a.find((child) => child.value === node)) == null ? void 0 : _b.path) != null ? _c : [];
3019
+ const original = resolver.getSourceNode(node);
3020
+ return (_c = (_b = (_a = parentNode.children) == null ? void 0 : _a.find((child) => child.value === original)) == null ? void 0 : _b.path) != null ? _c : [];
2689
3021
  }
2690
3022
  if (parentNode.type !== exports.NodeType.MultiNode) {
2691
3023
  return [];
2692
3024
  }
2693
- return findBasePath(parentNode);
3025
+ return findBasePath(parentNode, resolver);
2694
3026
  };
2695
3027
  class StringResolverPlugin {
3028
+ constructor() {
3029
+ this.propertiesToSkipCache = new Map();
3030
+ }
2696
3031
  applyResolver(resolver) {
2697
3032
  resolver.hooks.resolve.tap("string-resolver", (value, node, options) => {
2698
- var _a, _b, _c, _d;
3033
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2699
3034
  if (node.type === exports.NodeType.Empty || node.type === exports.NodeType.Unknown) {
2700
3035
  return null;
2701
3036
  }
2702
3037
  if (node.type === exports.NodeType.Value || node.type === exports.NodeType.Asset || node.type === exports.NodeType.View) {
2703
- const propsToSkip = new Set(((_b = (_a = node.plugins) == null ? void 0 : _a.stringResolver) == null ? void 0 : _b.propertiesToSkip) ? (_d = (_c = node.plugins) == null ? void 0 : _c.stringResolver) == null ? void 0 : _d.propertiesToSkip : []);
2704
- const nodePath = findBasePath(node);
3038
+ let propsToSkip;
3039
+ if (node.type === exports.NodeType.Asset || node.type === exports.NodeType.View) {
3040
+ propsToSkip = new Set((_c = (_b = (_a = node.plugins) == null ? void 0 : _a.stringResolver) == null ? void 0 : _b.propertiesToSkip) != null ? _c : ["exp"]);
3041
+ if ((_d = node.value) == null ? void 0 : _d.id) {
3042
+ this.propertiesToSkipCache.set(node.value.id, propsToSkip);
3043
+ }
3044
+ } else if (((_e = node.parent) == null ? void 0 : _e.type) === exports.NodeType.MultiNode && (((_g = (_f = node.parent) == null ? void 0 : _f.parent) == null ? void 0 : _g.type) === exports.NodeType.Asset || ((_i = (_h = node.parent) == null ? void 0 : _h.parent) == null ? void 0 : _i.type) === exports.NodeType.View) && ((_j = node.parent.parent.value) == null ? void 0 : _j.id) && this.propertiesToSkipCache.has(node.parent.parent.value.id)) {
3045
+ propsToSkip = this.propertiesToSkipCache.get(node.parent.parent.value.id);
3046
+ } else {
3047
+ propsToSkip = new Set(["exp"]);
3048
+ }
3049
+ const nodePath = findBasePath(node, resolver);
2705
3050
  if (nodePath.length > 0 && nodePath.some((segment) => propsToSkip.has(segment.toString()))) {
2706
3051
  return node.value;
2707
3052
  }
@@ -2721,7 +3066,7 @@ class ApplicabilityPlugin {
2721
3066
  let newNode = node;
2722
3067
  if ((node == null ? void 0 : node.type) === exports.NodeType.Applicability) {
2723
3068
  const isApplicable = options.evaluate(node.expression);
2724
- if (!isApplicable) {
3069
+ if (isApplicable === false) {
2725
3070
  return null;
2726
3071
  }
2727
3072
  newNode = node.value;
@@ -3027,7 +3372,8 @@ class FlowInstance {
3027
3372
  skipTransition: new tapableTs.SyncBailHook(),
3028
3373
  beforeTransition: new tapableTs.SyncWaterfallHook(),
3029
3374
  resolveTransitionNode: new tapableTs.SyncWaterfallHook(),
3030
- transition: new tapableTs.SyncHook()
3375
+ transition: new tapableTs.SyncHook(),
3376
+ afterTransition: new tapableTs.SyncHook()
3031
3377
  };
3032
3378
  this.id = id;
3033
3379
  this.flow = flow;
@@ -3074,7 +3420,7 @@ class FlowInstance {
3074
3420
  } else {
3075
3421
  const skipTransition = this.hooks.skipTransition.call(this.currentState);
3076
3422
  if (skipTransition) {
3077
- (_d = this.log) == null ? void 0 : _d.debug(`Skipping transition from ${this.currentState} b/c hook told us to`);
3423
+ (_d = this.log) == null ? void 0 : _d.debug(`Skipping transition from ${this.currentState.name} b/c hook told us to`);
3078
3424
  return;
3079
3425
  }
3080
3426
  }
@@ -3113,6 +3459,7 @@ class FlowInstance {
3113
3459
  this.hooks.onEnd.call(this.flow.onEnd);
3114
3460
  }
3115
3461
  this.hooks.transition.call(prevState, __spreadValues$5({}, newCurrentState));
3462
+ this.hooks.afterTransition.call(this);
3116
3463
  }
3117
3464
  }
3118
3465
 
@@ -3147,6 +3494,7 @@ class FlowController {
3147
3494
  this.start = this.start.bind(this);
3148
3495
  this.run = this.run.bind(this);
3149
3496
  this.transition = this.transition.bind(this);
3497
+ this.addNewFlow = this.addNewFlow.bind(this);
3150
3498
  }
3151
3499
  transition(stateTransition, options) {
3152
3500
  if (this.current === void 0) {
@@ -3155,20 +3503,9 @@ class FlowController {
3155
3503
  this.current.transition(stateTransition, options);
3156
3504
  }
3157
3505
  addNewFlow(flow) {
3158
- return __async$1(this, null, function* () {
3159
- this.navStack.push(flow);
3160
- this.current = flow;
3161
- flow.hooks.transition.tap("flow-controller", (_oldState, newState) => __async$1(this, null, function* () {
3162
- var _a, _b;
3163
- if (newState.value.state_type === "FLOW") {
3164
- (_a = this.log) == null ? void 0 : _a.debug(`Got FLOW state. Loading flow ${newState.value.ref}`);
3165
- const endState = yield this.run(newState.value.ref);
3166
- (_b = this.log) == null ? void 0 : _b.debug(`Flow ended. Using outcome: ${endState.outcome}`);
3167
- flow.transition(endState.outcome);
3168
- }
3169
- }));
3170
- this.hooks.flow.call(flow);
3171
- });
3506
+ this.navStack.push(flow);
3507
+ this.current = flow;
3508
+ this.hooks.flow.call(flow);
3172
3509
  }
3173
3510
  run(startState) {
3174
3511
  return __async$1(this, null, function* () {
@@ -3183,6 +3520,18 @@ class FlowController {
3183
3520
  (_a = this.log) == null ? void 0 : _a.debug(`Starting flow: ${startState}`);
3184
3521
  const flow = new FlowInstance(startState, startFlow, { logger: this.log });
3185
3522
  this.addNewFlow(flow);
3523
+ flow.hooks.afterTransition.tap("flow-controller", (flowInstance) => {
3524
+ var _a2, _b, _c;
3525
+ if (((_a2 = flowInstance.currentState) == null ? void 0 : _a2.value.state_type) === "FLOW") {
3526
+ const subflowId = (_b = flowInstance.currentState) == null ? void 0 : _b.value.ref;
3527
+ (_c = this.log) == null ? void 0 : _c.debug(`Loading subflow ${subflowId}`);
3528
+ this.run(subflowId).then((subFlowEndState) => {
3529
+ var _a3;
3530
+ (_a3 = this.log) == null ? void 0 : _a3.debug(`Subflow ended. Using outcome: ${subFlowEndState.outcome}`);
3531
+ flowInstance.transition(subFlowEndState == null ? void 0 : subFlowEndState.outcome);
3532
+ });
3533
+ }
3534
+ });
3186
3535
  const end = yield flow.start();
3187
3536
  this.navStack.pop();
3188
3537
  if (this.navStack.length > 0) {
@@ -3235,11 +3584,18 @@ class ValidationBindingTrackerViewPlugin {
3235
3584
  getBindings() {
3236
3585
  return this.trackedBindings;
3237
3586
  }
3587
+ trackBinding(binding) {
3588
+ var _a, _b;
3589
+ if (this.trackedBindings.has(binding)) {
3590
+ return;
3591
+ }
3592
+ this.trackedBindings.add(binding);
3593
+ (_b = (_a = this.options.callbacks) == null ? void 0 : _a.onAdd) == null ? void 0 : _b.call(_a, binding);
3594
+ }
3238
3595
  applyResolver(resolver) {
3239
3596
  this.trackedBindings.clear();
3240
3597
  const tracked = new Map();
3241
3598
  const sections = new Map();
3242
- const seenBindings = new Set();
3243
3599
  let lastViewUpdateChangeSet;
3244
3600
  const nodeTree = new Map();
3245
3601
  let lastComputedBindingTree = new Map();
@@ -3286,31 +3642,34 @@ class ValidationBindingTrackerViewPlugin {
3286
3642
  parent = parent.parent;
3287
3643
  }
3288
3644
  }
3289
- if (!seenBindings.has(parsed)) {
3290
- seenBindings.add(parsed);
3291
- (_d = (_c = this.options.callbacks) == null ? void 0 : _c.onAdd) == null ? void 0 : _d.call(_c, parsed);
3292
- }
3645
+ this.trackedBindings.add(parsed);
3646
+ (_d = (_c = this.options.callbacks) == null ? void 0 : _c.onAdd) == null ? void 0 : _d.call(_c, parsed);
3293
3647
  };
3294
3648
  return __spreadProps$3(__spreadValues$4({}, options), {
3295
3649
  validation: __spreadProps$3(__spreadValues$4({}, options.validation), {
3296
3650
  get: (binding, getOptions) => {
3297
- var _a;
3651
+ var _a, _b;
3298
3652
  if (getOptions == null ? void 0 : getOptions.track) {
3299
3653
  track(binding);
3300
3654
  }
3301
- const eow = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding);
3302
- if ((eow == null ? void 0 : eow.displayTarget) === void 0 || (eow == null ? void 0 : eow.displayTarget) === "field") {
3303
- return eow;
3655
+ const eows = (_b = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding)) == null ? void 0 : _b.getAll(getOptions);
3656
+ const firstFieldEOW = eows == null ? void 0 : eows.find((eow) => eow.displayTarget === "field" || eow.displayTarget === void 0);
3657
+ return firstFieldEOW;
3658
+ },
3659
+ getValidationsForBinding(binding, getOptions) {
3660
+ var _a, _b, _c;
3661
+ if (getOptions == null ? void 0 : getOptions.track) {
3662
+ track(binding);
3304
3663
  }
3305
- return void 0;
3664
+ return (_c = (_b = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding)) == null ? void 0 : _b.getAll(getOptions)) != null ? _c : [];
3306
3665
  },
3307
3666
  getChildren: (type) => {
3308
3667
  var _a;
3309
3668
  const validations = new Array();
3310
3669
  (_a = lastComputedBindingTree.get(node)) == null ? void 0 : _a.forEach((binding) => {
3311
- var _a2;
3312
- const eow = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding);
3313
- if (eow && type === eow.displayTarget) {
3670
+ var _a2, _b;
3671
+ const eow = (_b = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding)) == null ? void 0 : _b.get();
3672
+ if (eow && (type === void 0 || type === eow.displayTarget)) {
3314
3673
  validations.push(eow);
3315
3674
  }
3316
3675
  });
@@ -3320,8 +3679,8 @@ class ValidationBindingTrackerViewPlugin {
3320
3679
  var _a;
3321
3680
  const validations = new Array();
3322
3681
  (_a = lastSectionBindingTree.get(node)) == null ? void 0 : _a.forEach((binding) => {
3323
- var _a2;
3324
- const eow = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding);
3682
+ var _a2, _b;
3683
+ const eow = (_b = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding)) == null ? void 0 : _b.get();
3325
3684
  if (eow && eow.displayTarget === "section") {
3326
3685
  validations.push(eow);
3327
3686
  }
@@ -3340,7 +3699,7 @@ class ValidationBindingTrackerViewPlugin {
3340
3699
  });
3341
3700
  });
3342
3701
  resolver.hooks.afterNodeUpdate.tap(CONTEXT, (node, parent, update) => {
3343
- var _a, _b, _c;
3702
+ var _a, _b;
3344
3703
  if (parent) {
3345
3704
  addToTree(node, parent);
3346
3705
  }
@@ -3355,7 +3714,7 @@ class ValidationBindingTrackerViewPlugin {
3355
3714
  currentBindingTree.set(node, (_b = lastComputedBindingTree.get(node)) != null ? _b : new Set());
3356
3715
  }
3357
3716
  if (node === resolver.root) {
3358
- this.trackedBindings = (_c = currentBindingTree.get(node)) != null ? _c : new Set();
3717
+ this.trackedBindings = new Set(currentBindingTree.get(node));
3359
3718
  lastComputedBindingTree = currentBindingTree;
3360
3719
  lastSectionBindingTree.clear();
3361
3720
  sections.forEach((nodeSet, sectionNode) => {
@@ -3397,11 +3756,23 @@ var __spreadValues$3 = (a, b) => {
3397
3756
  return a;
3398
3757
  };
3399
3758
  var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
3759
+ const SCHEMA_VALIDATION_PROVIDER_NAME = "schema";
3760
+ const VIEW_VALIDATION_PROVIDER_NAME = "view";
3761
+ const VALIDATION_PROVIDER_NAME_SYMBOL = Symbol.for("validation-provider-name");
3762
+ function isSubset(subset, containingSet) {
3763
+ if (subset.size > containingSet.size)
3764
+ return false;
3765
+ for (const entry of subset)
3766
+ if (!containingSet.has(entry))
3767
+ return false;
3768
+ return true;
3769
+ }
3400
3770
  function createStatefulValidationObject(obj) {
3401
3771
  return {
3402
3772
  value: obj,
3403
3773
  type: obj.severity,
3404
- state: "none"
3774
+ state: "none",
3775
+ isBlockingNavigation: false
3405
3776
  };
3406
3777
  }
3407
3778
  class ValidatedBinding {
@@ -3416,44 +3787,68 @@ class ValidatedBinding {
3416
3787
  possibleValidations.forEach((vObj) => {
3417
3788
  const { trigger } = vObj;
3418
3789
  if (this.validationsByState[trigger]) {
3419
- this.validationsByState[trigger].push(createStatefulValidationObject(vObj));
3790
+ const statefulValidationObject = createStatefulValidationObject(vObj);
3791
+ this.validationsByState[trigger].push(statefulValidationObject);
3420
3792
  } else {
3421
3793
  log == null ? void 0 : log.warn(`Unknown validation trigger: ${trigger}`);
3422
3794
  }
3423
3795
  });
3424
3796
  this.weakBindings = weakBindings != null ? weakBindings : new Set();
3425
3797
  }
3798
+ get allValidations() {
3799
+ return Object.values(this.validationsByState).flat();
3800
+ }
3801
+ checkIfBlocking(statefulObj) {
3802
+ if (statefulObj.state === "active") {
3803
+ const { isBlockingNavigation } = statefulObj;
3804
+ return isBlockingNavigation;
3805
+ }
3806
+ return false;
3807
+ }
3808
+ getAll() {
3809
+ return this.applicableValidations.reduce((all, statefulObj) => {
3810
+ if (statefulObj.state === "active" && statefulObj.response) {
3811
+ return [
3812
+ ...all,
3813
+ __spreadProps$2(__spreadValues$3({}, statefulObj.response), {
3814
+ blocking: this.checkIfBlocking(statefulObj)
3815
+ })
3816
+ ];
3817
+ }
3818
+ return all;
3819
+ }, []);
3820
+ }
3426
3821
  get() {
3427
- const firstError = this.applicableValidations.find((statefulObj) => {
3428
- const blocking = this.currentPhase === "navigation" ? statefulObj.value.blocking : true;
3429
- return statefulObj.state === "active" && blocking !== false;
3822
+ const firstInvalid = this.applicableValidations.find((statefulObj) => {
3823
+ return statefulObj.state === "active" && statefulObj.response;
3430
3824
  });
3431
- if ((firstError == null ? void 0 : firstError.state) === "active") {
3432
- return firstError.response;
3825
+ if ((firstInvalid == null ? void 0 : firstInvalid.state) === "active") {
3826
+ return __spreadProps$2(__spreadValues$3({}, firstInvalid.response), {
3827
+ blocking: this.checkIfBlocking(firstInvalid)
3828
+ });
3433
3829
  }
3434
3830
  }
3435
- runApplicableValidations(runner, canDismiss) {
3436
- this.applicableValidations = this.applicableValidations.map((obj) => {
3831
+ runApplicableValidations(runner, canDismiss, phase) {
3832
+ this.applicableValidations = this.applicableValidations.map((originalValue) => {
3437
3833
  var _a, _b, _c;
3438
- if (obj.state === "dismissed") {
3439
- return obj;
3834
+ if (originalValue.state === "dismissed") {
3835
+ return originalValue;
3440
3836
  }
3441
- const blocking = (_a = obj.value.blocking) != null ? _a : obj.value.severity === "warning" && "once" || obj.value.severity === "error" && true;
3442
- const dismissable = canDismiss && blocking === "once";
3443
- if (this.currentPhase === "navigation" && obj.state === "active" && dismissable) {
3837
+ const blocking = (_a = originalValue.value.blocking) != null ? _a : originalValue.value.severity === "warning" && "once" || true;
3838
+ const obj = timm.setIn(originalValue, ["value", "blocking"], blocking);
3839
+ const isBlockingNavigation = blocking === true || blocking === "once" && !canDismiss;
3840
+ if (phase === "navigation" && obj.state === "active" && obj.value.blocking !== true) {
3444
3841
  if (obj.value.severity === "warning") {
3445
3842
  const warn = obj;
3446
- if (warn.dismissable && warn.response.dismiss) {
3843
+ if (warn.dismissable && warn.response.dismiss && (warn.response.blocking !== "once" || !warn.response.blocking)) {
3447
3844
  warn.response.dismiss();
3448
3845
  } else {
3846
+ if ((warn == null ? void 0 : warn.response.blocking) === "once") {
3847
+ warn.response.blocking = false;
3848
+ }
3449
3849
  warn.dismissable = true;
3450
3850
  }
3451
- return obj;
3452
- }
3453
- if (obj.value.severity === "error") {
3454
- const err = obj;
3455
- err.state = "none";
3456
- return obj;
3851
+ return warn;
3457
3852
  }
3458
3853
  }
3459
3854
  const response = runner(obj.value);
@@ -3461,7 +3856,8 @@ class ValidatedBinding {
3461
3856
  type: obj.type,
3462
3857
  value: obj.value,
3463
3858
  state: response ? "active" : "none",
3464
- dismissable: obj.value.severity === "warning" && this.currentPhase === "navigation",
3859
+ isBlockingNavigation,
3860
+ dismissable: obj.value.severity === "warning" && phase === "navigation",
3465
3861
  response: response ? __spreadProps$2(__spreadValues$3({}, obj.value), {
3466
3862
  message: (_b = response.message) != null ? _b : "Something is broken",
3467
3863
  severity: obj.value.severity,
@@ -3479,11 +3875,12 @@ class ValidatedBinding {
3479
3875
  });
3480
3876
  }
3481
3877
  update(phase, canDismiss, runner) {
3878
+ const newApplicableValidations = [];
3482
3879
  if (phase === "load" && this.currentPhase !== void 0) {
3483
3880
  return;
3484
3881
  }
3485
3882
  if (this.currentPhase === "navigation" || phase === this.currentPhase) {
3486
- this.runApplicableValidations(runner, canDismiss);
3883
+ this.runApplicableValidations(runner, canDismiss, phase);
3487
3884
  return;
3488
3885
  }
3489
3886
  if (phase === "load") {
@@ -3496,14 +3893,19 @@ class ValidatedBinding {
3496
3893
  ...this.validationsByState.change
3497
3894
  ];
3498
3895
  } else if (phase === "navigation" && (this.currentPhase === "load" || this.currentPhase === "change")) {
3896
+ this.applicableValidations.forEach((element) => {
3897
+ if (!(element.type === "error" && element.state === "active" && element.isBlockingNavigation === false)) {
3898
+ newApplicableValidations.push(element);
3899
+ }
3900
+ });
3499
3901
  this.applicableValidations = [
3500
- ...this.applicableValidations,
3501
- ...this.currentPhase === "load" ? this.validationsByState.change : [],
3502
- ...this.validationsByState.navigation
3902
+ ...newApplicableValidations,
3903
+ ...this.validationsByState.navigation,
3904
+ ...this.currentPhase === "load" ? this.validationsByState.change : []
3503
3905
  ];
3504
3906
  this.currentPhase = "navigation";
3505
3907
  }
3506
- this.runApplicableValidations(runner, canDismiss);
3908
+ this.runApplicableValidations(runner, canDismiss, phase);
3507
3909
  }
3508
3910
  }
3509
3911
  class ValidationController {
@@ -3511,34 +3913,63 @@ class ValidationController {
3511
3913
  this.hooks = {
3512
3914
  createValidatorRegistry: new tapableTs.SyncHook(),
3513
3915
  onAddValidation: new tapableTs.SyncWaterfallHook(),
3514
- onRemoveValidation: new tapableTs.SyncWaterfallHook()
3916
+ onRemoveValidation: new tapableTs.SyncWaterfallHook(),
3917
+ resolveValidationProviders: new tapableTs.SyncWaterfallHook(),
3918
+ onTrackBinding: new tapableTs.SyncHook()
3515
3919
  };
3516
3920
  this.validations = new Map();
3517
3921
  this.weakBindingTracker = new Set();
3518
- this.lastActiveBindings = new Set();
3519
3922
  this.schema = schema;
3520
3923
  this.options = options;
3521
- this.providers = [schema];
3924
+ this.reset();
3522
3925
  }
3523
3926
  setOptions(options) {
3524
3927
  this.options = options;
3525
3928
  }
3526
3929
  getDataMiddleware() {
3527
3930
  return [
3931
+ {
3932
+ set: (transaction, options, next) => {
3933
+ var _a;
3934
+ return (_a = next == null ? void 0 : next.set(transaction, options)) != null ? _a : [];
3935
+ },
3936
+ get: (binding, options, next) => {
3937
+ return next == null ? void 0 : next.get(binding, options);
3938
+ },
3939
+ delete: (binding, options, next) => {
3940
+ this.validations = removeBindingAndChildrenFromMap(this.validations, binding);
3941
+ return next == null ? void 0 : next.delete(binding, options);
3942
+ }
3943
+ },
3528
3944
  new ValidationMiddleware((binding) => {
3945
+ var _a;
3529
3946
  if (!this.options) {
3530
3947
  return;
3531
3948
  }
3532
3949
  this.updateValidationsForBinding(binding, "change", this.options);
3533
3950
  const strongValidation = this.getValidationForBinding(binding);
3534
- if (strongValidation == null ? void 0 : strongValidation.get())
3951
+ if (((_a = strongValidation == null ? void 0 : strongValidation.get()) == null ? void 0 : _a.severity) === "error") {
3535
3952
  return strongValidation.get();
3953
+ }
3536
3954
  const newInvalidBindings = new Set();
3537
- for (const [, weakValidation] of Array.from(this.validations)) {
3538
- if (caresAboutDataChanges(new Set([binding]), weakValidation.weakBindings) && (weakValidation == null ? void 0 : weakValidation.get())) {
3539
- weakValidation == null ? void 0 : weakValidation.weakBindings.forEach(newInvalidBindings.add, newInvalidBindings);
3955
+ this.validations.forEach((weakValidation, strongBinding) => {
3956
+ var _a2;
3957
+ if (caresAboutDataChanges(new Set([binding]), weakValidation.weakBindings) && ((_a2 = weakValidation == null ? void 0 : weakValidation.get()) == null ? void 0 : _a2.severity) === "error") {
3958
+ weakValidation == null ? void 0 : weakValidation.weakBindings.forEach((weakBinding) => {
3959
+ if (weakBinding === strongBinding) {
3960
+ newInvalidBindings.add({
3961
+ binding: weakBinding,
3962
+ isStrong: true
3963
+ });
3964
+ } else {
3965
+ newInvalidBindings.add({
3966
+ binding: weakBinding,
3967
+ isStrong: false
3968
+ });
3969
+ }
3970
+ });
3540
3971
  }
3541
- }
3972
+ });
3542
3973
  if (newInvalidBindings.size > 0) {
3543
3974
  return newInvalidBindings;
3544
3975
  }
@@ -3548,6 +3979,35 @@ class ValidationController {
3548
3979
  }) })
3549
3980
  ];
3550
3981
  }
3982
+ getValidationProviders() {
3983
+ if (this.providers) {
3984
+ return this.providers;
3985
+ }
3986
+ this.providers = this.hooks.resolveValidationProviders.call([
3987
+ {
3988
+ source: SCHEMA_VALIDATION_PROVIDER_NAME,
3989
+ provider: this.schema
3990
+ },
3991
+ {
3992
+ source: VIEW_VALIDATION_PROVIDER_NAME,
3993
+ provider: {
3994
+ getValidationsForBinding: (binding) => {
3995
+ var _a, _b;
3996
+ return (_b = (_a = this.viewValidationProvider) == null ? void 0 : _a.getValidationsForBinding) == null ? void 0 : _b.call(_a, binding);
3997
+ },
3998
+ getValidationsForView: () => {
3999
+ var _a, _b;
4000
+ return (_b = (_a = this.viewValidationProvider) == null ? void 0 : _a.getValidationsForView) == null ? void 0 : _b.call(_a);
4001
+ }
4002
+ }
4003
+ }
4004
+ ]);
4005
+ return this.providers;
4006
+ }
4007
+ reset() {
4008
+ this.validations.clear();
4009
+ this.tracker = void 0;
4010
+ }
3551
4011
  onView(view) {
3552
4012
  this.validations.clear();
3553
4013
  if (!this.options) {
@@ -3556,7 +4016,7 @@ class ValidationController {
3556
4016
  const bindingTrackerPlugin = new ValidationBindingTrackerViewPlugin(__spreadProps$2(__spreadValues$3({}, this.options), {
3557
4017
  callbacks: {
3558
4018
  onAdd: (binding) => {
3559
- if (!this.options) {
4019
+ if (!this.options || this.getValidationForBinding(binding) !== void 0) {
3560
4020
  return;
3561
4021
  }
3562
4022
  const originalValue = this.options.model.get(binding);
@@ -3564,26 +4024,35 @@ class ValidationController {
3564
4024
  ignoreDefaultValue: true
3565
4025
  });
3566
4026
  if (originalValue !== withoutDefault) {
3567
- this.options.model.set([[binding, originalValue]]);
4027
+ this.options.model.set([[binding, originalValue]], {
4028
+ silent: true
4029
+ });
3568
4030
  }
3569
4031
  this.updateValidationsForBinding(binding, "load", this.options, () => {
3570
4032
  view.update(new Set([binding]));
3571
4033
  });
4034
+ this.hooks.onTrackBinding.call(binding);
3572
4035
  }
3573
4036
  }
3574
4037
  }));
3575
4038
  this.tracker = bindingTrackerPlugin;
3576
- this.providers = [this.schema, view];
4039
+ this.viewValidationProvider = view;
3577
4040
  bindingTrackerPlugin.apply(view);
3578
4041
  }
3579
- updateValidationsForBinding(binding, trigger, context, onDismiss) {
4042
+ updateValidationsForBinding(binding, trigger, validationContext, onDismiss) {
3580
4043
  var _a;
4044
+ const context = validationContext != null ? validationContext : this.options;
4045
+ if (!context) {
4046
+ throw new Error(`Context is required for executing validations`);
4047
+ }
3581
4048
  if (trigger === "load") {
3582
- const possibleValidations = this.providers.reduce((vals, provider) => {
3583
- var _a2, _b;
4049
+ const possibleValidations = this.getValidationProviders().reduce((vals, provider) => {
4050
+ var _a2, _b, _c, _d;
3584
4051
  return [
3585
4052
  ...vals,
3586
- ...(_b = (_a2 = provider.getValidationsForBinding) == null ? void 0 : _a2.call(provider, binding)) != null ? _b : []
4053
+ ...(_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), {
4054
+ [VALIDATION_PROVIDER_NAME_SYMBOL]: provider.source
4055
+ }))) != null ? _d : []
3587
4056
  ];
3588
4057
  }, []);
3589
4058
  if (possibleValidations.length === 0) {
@@ -3593,7 +4062,7 @@ class ValidationController {
3593
4062
  }
3594
4063
  const trackedValidations = this.validations.get(binding);
3595
4064
  trackedValidations == null ? void 0 : trackedValidations.update(trigger, true, (validationObj) => {
3596
- const response = this.validationRunner(validationObj, context, binding);
4065
+ const response = this.validationRunner(validationObj, binding, context);
3597
4066
  if (this.weakBindingTracker.size > 0) {
3598
4067
  const t = this.validations.get(binding);
3599
4068
  this.weakBindingTracker.forEach((b) => t.weakBindings.add(b));
@@ -3604,27 +4073,33 @@ class ValidationController {
3604
4073
  this.validations.forEach((validation, vBinding) => {
3605
4074
  if (vBinding !== binding && caresAboutDataChanges(new Set([binding]), validation.weakBindings)) {
3606
4075
  validation.update(trigger, true, (validationObj) => {
3607
- const response = this.validationRunner(validationObj, context, binding);
4076
+ const response = this.validationRunner(validationObj, vBinding, context);
3608
4077
  return response ? { message: response.message } : void 0;
3609
4078
  });
3610
4079
  }
3611
4080
  });
3612
4081
  }
3613
4082
  }
3614
- validationRunner(validationObj, context, binding) {
3615
- const handler = this.getValidator(validationObj.type);
4083
+ validationRunner(validationObj, binding, context = this.options) {
4084
+ var _a;
4085
+ if (!context) {
4086
+ throw new Error("No context provided to validation runner");
4087
+ }
4088
+ const handler = (_a = validationObj.handler) != null ? _a : this.getValidator(validationObj.type);
3616
4089
  const weakBindings = new Set();
3617
4090
  const model = {
3618
- get(b, options = { includeInvalid: true }) {
4091
+ get(b, options) {
3619
4092
  weakBindings.add(isBinding(b) ? binding : context.parseBinding(b));
3620
- return context.model.get(b, options);
4093
+ return context.model.get(b, __spreadProps$2(__spreadValues$3({}, options), { includeInvalid: true }));
3621
4094
  },
3622
- set: context.model.set
4095
+ set: context.model.set,
4096
+ delete: context.model.delete
3623
4097
  };
3624
4098
  const result = handler == null ? void 0 : handler(__spreadProps$2(__spreadValues$3({}, context), {
3625
4099
  evaluate: (exp, options = { model }) => context.evaluate(exp, options),
3626
4100
  model,
3627
- validation: validationObj
4101
+ validation: validationObj,
4102
+ schemaType: this.schema.getType(binding)
3628
4103
  }), context.model.get(binding, {
3629
4104
  includeInvalid: true,
3630
4105
  formatted: validationObj.dataTarget === "formatted"
@@ -3648,29 +4123,27 @@ class ValidationController {
3648
4123
  }
3649
4124
  }
3650
4125
  updateValidationsForView(trigger) {
3651
- const { activeBindings } = this;
3652
- const canDismiss = trigger !== "navigation" || this.setCompare(this.lastActiveBindings, activeBindings);
3653
- this.getBindings().forEach((binding) => {
3654
- var _a;
3655
- (_a = this.validations.get(binding)) == null ? void 0 : _a.update(trigger, canDismiss, (obj) => {
3656
- if (!this.options) {
3657
- return;
3658
- }
3659
- return this.validationRunner(obj, this.options, binding);
4126
+ const isNavigationTrigger = trigger === "navigation";
4127
+ const lastActiveBindings = this.activeBindings;
4128
+ const updateValidations = (dismissValidations) => {
4129
+ this.getBindings().forEach((binding) => {
4130
+ var _a;
4131
+ (_a = this.validations.get(binding)) == null ? void 0 : _a.update(trigger, dismissValidations, (obj) => {
4132
+ if (!this.options) {
4133
+ return;
4134
+ }
4135
+ return this.validationRunner(obj, binding, this.options);
4136
+ });
3660
4137
  });
3661
- });
3662
- if (trigger === "navigation") {
3663
- this.lastActiveBindings = activeBindings;
4138
+ };
4139
+ updateValidations(!isNavigationTrigger);
4140
+ if (isNavigationTrigger) {
4141
+ const { activeBindings } = this;
4142
+ if (isSubset(activeBindings, lastActiveBindings)) {
4143
+ updateValidations(true);
4144
+ }
3664
4145
  }
3665
4146
  }
3666
- setCompare(set1, set2) {
3667
- if (set1.size !== set2.size)
3668
- return false;
3669
- for (const entry of set1)
3670
- if (!set2.has(entry))
3671
- return false;
3672
- return true;
3673
- }
3674
4147
  get activeBindings() {
3675
4148
  return new Set(Array.from(this.getBindings()).filter((b) => {
3676
4149
  var _a;
@@ -3690,19 +4163,30 @@ class ValidationController {
3690
4163
  var _a, _b;
3691
4164
  return (_b = (_a = this.tracker) == null ? void 0 : _a.getBindings()) != null ? _b : new Set();
3692
4165
  }
4166
+ trackBinding(binding) {
4167
+ var _a;
4168
+ (_a = this.tracker) == null ? void 0 : _a.trackBinding(binding);
4169
+ }
3693
4170
  validateView(trigger = "navigation") {
3694
- var _a, _b;
3695
4171
  this.updateValidationsForView(trigger);
3696
4172
  const validations = new Map();
3697
- for (const b of this.getBindings()) {
3698
- const invalid = (_a = this.getValidationForBinding(b)) == null ? void 0 : _a.get();
3699
- if (invalid) {
3700
- (_b = this.options) == null ? void 0 : _b.logger.debug(`Validation on binding: ${b.asString()} is preventing navigation. ${JSON.stringify(invalid)}`);
3701
- validations.set(b, invalid);
3702
- }
3703
- }
4173
+ let canTransition = true;
4174
+ this.getBindings().forEach((b) => {
4175
+ var _a;
4176
+ const allValidations = (_a = this.getValidationForBinding(b)) == null ? void 0 : _a.getAll();
4177
+ allValidations == null ? void 0 : allValidations.forEach((v) => {
4178
+ var _a2;
4179
+ if (trigger === "navigation" && v.blocking) {
4180
+ (_a2 = this.options) == null ? void 0 : _a2.logger.debug(`Validation on binding: ${b.asString()} is preventing navigation. ${JSON.stringify(v)}`);
4181
+ canTransition = false;
4182
+ }
4183
+ if (!validations.has(b)) {
4184
+ validations.set(b, v);
4185
+ }
4186
+ });
4187
+ });
3704
4188
  return {
3705
- canTransition: validations.size === 0,
4189
+ canTransition,
3706
4190
  validations: validations.size ? validations : void 0
3707
4191
  };
3708
4192
  }
@@ -3712,8 +4196,7 @@ class ValidationController {
3712
4196
  forView(parser) {
3713
4197
  return {
3714
4198
  _getValidationForBinding: (binding) => {
3715
- var _a;
3716
- return (_a = this.getValidationForBinding(isBinding(binding) ? binding : parser(binding))) == null ? void 0 : _a.get();
4199
+ return this.getValidationForBinding(isBinding(binding) ? binding : parser(binding));
3717
4200
  },
3718
4201
  getAll: () => {
3719
4202
  const bindings = this.getBindings();
@@ -3733,6 +4216,9 @@ class ValidationController {
3733
4216
  get() {
3734
4217
  throw new Error("Error Access be provided by the view plugin");
3735
4218
  },
4219
+ getValidationsForBinding() {
4220
+ throw new Error("Error rollup should be provided by the view plugin");
4221
+ },
3736
4222
  getChildren() {
3737
4223
  throw new Error("Error rollup should be provided by the view plugin");
3738
4224
  },
@@ -3743,7 +4229,7 @@ class ValidationController {
3743
4229
  throw new Error("Tracking should be provided by the view plugin");
3744
4230
  },
3745
4231
  register: () => {
3746
- throw new Error("Section funcationality hould be provided by the view plugin");
4232
+ throw new Error("Section functionality should be provided by the view plugin");
3747
4233
  },
3748
4234
  type: (binding) => this.schema.getType(isBinding(binding) ? binding : parser(binding))
3749
4235
  };
@@ -3859,10 +4345,11 @@ class AssetTransformCorePlugin {
3859
4345
  };
3860
4346
  };
3861
4347
  resolver.hooks.beforeResolve.tap("asset-transform", (node, options) => {
4348
+ var _a;
3862
4349
  if (node && (node.type === "asset" || node.type === "view")) {
3863
4350
  const transform = this.registry.get(node.value);
3864
4351
  if (transform == null ? void 0 : transform.beforeResolve) {
3865
- const store = getStore(node, this.beforeResolveSymbol);
4352
+ const store = getStore((_a = options.node) != null ? _a : node, this.beforeResolveSymbol);
3866
4353
  return transform.beforeResolve(node, options, store);
3867
4354
  }
3868
4355
  }
@@ -3940,14 +4427,26 @@ class ViewController {
3940
4427
  }
3941
4428
  });
3942
4429
  });
3943
- options.model.hooks.onUpdate.tap("viewController", (updates) => {
4430
+ const update = (updates) => {
3944
4431
  if (this.currentView) {
3945
4432
  if (this.optimizeUpdates) {
3946
- this.queueUpdate(new Set(updates.map((t) => t.binding)));
4433
+ this.queueUpdate(updates);
3947
4434
  } else {
3948
4435
  this.currentView.update();
3949
4436
  }
3950
4437
  }
4438
+ };
4439
+ options.model.hooks.onUpdate.tap("viewController", (updates) => {
4440
+ update(new Set(updates.map((t) => t.binding)));
4441
+ });
4442
+ options.model.hooks.onDelete.tap("viewController", (binding) => {
4443
+ const parentBinding = binding.parent();
4444
+ const property = binding.key();
4445
+ if (typeof property === "number" && parentBinding) {
4446
+ update(new Set([parentBinding]));
4447
+ } else {
4448
+ update(new Set([binding]));
4449
+ }
3951
4450
  });
3952
4451
  }
3953
4452
  queueUpdate(bindings) {
@@ -3992,6 +4491,25 @@ class ViewController {
3992
4491
  }
3993
4492
  }
3994
4493
 
4494
+ class ReadOnlyDataController {
4495
+ constructor(controller, logger) {
4496
+ this.controller = controller;
4497
+ this.logger = logger;
4498
+ }
4499
+ get(binding, options) {
4500
+ return this.controller.get(binding, options);
4501
+ }
4502
+ set(transaction, options) {
4503
+ var _a;
4504
+ (_a = this.logger) == null ? void 0 : _a.error("Error: Tried to set in a read only instance of the DataController");
4505
+ return [];
4506
+ }
4507
+ delete(binding, options) {
4508
+ var _a;
4509
+ (_a = this.logger) == null ? void 0 : _a.error("Error: Tried to delete in a read only instance of the DataController");
4510
+ }
4511
+ }
4512
+
3995
4513
  class DataController {
3996
4514
  constructor(model, options) {
3997
4515
  this.hooks = {
@@ -4048,16 +4566,19 @@ class DataController {
4048
4566
  });
4049
4567
  }
4050
4568
  const setUpdates = normalizedTransaction.reduce((updates, [binding, newVal]) => {
4051
- var _a;
4569
+ var _a, _b;
4052
4570
  const oldVal = this.get(binding, { includeInvalid: true });
4053
- if (!dequal.dequal(oldVal, newVal)) {
4054
- updates.push({
4055
- binding,
4056
- newValue: newVal,
4057
- oldValue: oldVal
4058
- });
4571
+ const update = {
4572
+ binding,
4573
+ newValue: newVal,
4574
+ oldValue: oldVal
4575
+ };
4576
+ if (dequal.dequal(oldVal, newVal)) {
4577
+ (_a = this.logger) == null ? void 0 : _a.debug(`Skipping update for path: ${binding.asString()}. Value was unchanged: ${oldVal}`);
4578
+ } else {
4579
+ updates.push(update);
4580
+ (_b = this.logger) == null ? void 0 : _b.debug(`Setting path: ${binding.asString()} from: ${oldVal} to: ${newVal}`);
4059
4581
  }
4060
- (_a = this.logger) == null ? void 0 : _a.debug(`Setting path: ${binding.asString()} from: ${oldVal} to: ${newVal}`);
4061
4582
  return updates;
4062
4583
  }, []);
4063
4584
  const result = this.getModel().set(normalizedTransaction, options);
@@ -4071,15 +4592,15 @@ class DataController {
4071
4592
  });
4072
4593
  this.hooks.onSet.call(normalizedTransaction);
4073
4594
  if (setUpdates.length > 0) {
4074
- this.hooks.onUpdate.call(setUpdates);
4595
+ this.hooks.onUpdate.call(setUpdates, options);
4075
4596
  }
4076
4597
  return result;
4077
4598
  }
4078
- resolve(binding) {
4079
- return Array.isArray(binding) || typeof binding === "string" ? this.pathResolver.parse(binding) : binding;
4599
+ resolve(binding, readOnly) {
4600
+ return Array.isArray(binding) || typeof binding === "string" ? this.pathResolver.parse(binding, { readOnly }) : binding;
4080
4601
  }
4081
4602
  get(binding, options) {
4082
- const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding);
4603
+ const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding, true);
4083
4604
  let result = this.getModel().get(resolved, options);
4084
4605
  if (result === void 0 && !(options == null ? void 0 : options.ignoreDefaultValue)) {
4085
4606
  const defaultVal = this.hooks.resolveDefaultValue.call(resolved);
@@ -4089,48 +4610,33 @@ class DataController {
4089
4610
  }
4090
4611
  if (options == null ? void 0 : options.formatted) {
4091
4612
  result = this.hooks.format.call(result, resolved);
4613
+ } else if ((options == null ? void 0 : options.formatted) === false) {
4614
+ result = this.hooks.deformat.call(result, resolved);
4092
4615
  }
4093
4616
  this.hooks.onGet.call(binding, result);
4094
4617
  return result;
4095
4618
  }
4096
- delete(binding) {
4097
- if (binding === void 0 || binding === null) {
4098
- throw new Error(`Invalid arguments: delete expects a data path (string)`);
4619
+ delete(binding, options) {
4620
+ if (typeof binding !== "string" && !Array.isArray(binding) && !(binding instanceof BindingInstance)) {
4621
+ throw new Error("Invalid arguments: delete expects a data path (string)");
4099
4622
  }
4100
- const resolved = this.resolve(binding);
4101
- this.hooks.onDelete.call(resolved);
4102
- this.deleteData(resolved);
4103
- }
4104
- getTrash() {
4105
- return this.trash;
4106
- }
4107
- addToTrash(binding) {
4108
- this.trash.add(binding);
4109
- }
4110
- deleteData(binding) {
4111
- const parentBinding = binding.parent();
4112
- const parentPath = parentBinding.asString();
4113
- const property = binding.key();
4114
- const existedBeforeDelete = Object.prototype.hasOwnProperty.call(this.get(parentBinding), property);
4115
- if (property !== void 0) {
4116
- const parent = parentBinding ? this.get(parentBinding) : void 0;
4117
- if (parentPath && Array.isArray(parent)) {
4118
- if (parent.length > property) {
4119
- this.set([[parentBinding, timm.removeAt(parent, property)]]);
4120
- }
4121
- } else if (parentPath && parent[property]) {
4122
- this.set([[parentBinding, timm.omit(parent, property)]]);
4123
- } else if (!parentPath) {
4124
- this.getModel().reset(timm.omit(this.get(""), property));
4125
- }
4126
- }
4127
- if (existedBeforeDelete && !this.get(binding)) {
4128
- this.addToTrash(binding);
4623
+ const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding, false);
4624
+ const parentBinding = resolved.parent();
4625
+ const property = resolved.key();
4626
+ const parentValue = this.get(parentBinding);
4627
+ const existedBeforeDelete = typeof parentValue === "object" && parentValue !== null && Object.prototype.hasOwnProperty.call(parentValue, property);
4628
+ this.getModel().delete(resolved, options);
4629
+ if (existedBeforeDelete && !this.get(resolved)) {
4630
+ this.trash.add(resolved);
4129
4631
  }
4632
+ this.hooks.onDelete.call(resolved);
4130
4633
  }
4131
4634
  serialize() {
4132
4635
  return this.hooks.serialize.call(this.get(""));
4133
4636
  }
4637
+ makeReadOnly() {
4638
+ return new ReadOnlyDataController(this, this.logger);
4639
+ }
4134
4640
  }
4135
4641
 
4136
4642
  var __defProp$1 = Object.defineProperty;
@@ -4187,10 +4693,15 @@ class ConstantsController {
4187
4693
  this.tempStore.set(namespace, new LocalModel(data));
4188
4694
  }
4189
4695
  }
4190
- clearTemporaryValues() {
4191
- this.tempStore.forEach((value) => {
4192
- value.reset();
4193
- });
4696
+ clearTemporaryValues(namespace) {
4697
+ var _a;
4698
+ if (namespace) {
4699
+ (_a = this.tempStore.get(namespace)) == null ? void 0 : _a.reset();
4700
+ } else {
4701
+ this.tempStore.forEach((value) => {
4702
+ value.reset();
4703
+ });
4704
+ }
4194
4705
  }
4195
4706
  }
4196
4707
 
@@ -4228,6 +4739,39 @@ class FlowExpPlugin {
4228
4739
  }
4229
4740
  }
4230
4741
 
4742
+ const createFormatFunction = (schema) => {
4743
+ const handler = (ctx, value, formatName) => {
4744
+ var _a, _b;
4745
+ return (_b = (_a = schema.getFormatterForType({ type: formatName })) == null ? void 0 : _a.format(value)) != null ? _b : value;
4746
+ };
4747
+ return handler;
4748
+ };
4749
+ class DefaultExpPlugin {
4750
+ constructor() {
4751
+ this.name = "flow-exp-plugin";
4752
+ }
4753
+ apply(player) {
4754
+ let formatFunction;
4755
+ player.hooks.schema.tap(this.name, (schemaController) => {
4756
+ formatFunction = createFormatFunction(schemaController);
4757
+ });
4758
+ player.hooks.expressionEvaluator.tap(this.name, (expEvaluator) => {
4759
+ if (formatFunction) {
4760
+ expEvaluator.addExpressionFunction("format", formatFunction);
4761
+ }
4762
+ expEvaluator.addExpressionFunction("log", (ctx, ...args) => {
4763
+ player.logger.info(...args);
4764
+ });
4765
+ expEvaluator.addExpressionFunction("debug", (ctx, ...args) => {
4766
+ player.logger.debug(...args);
4767
+ });
4768
+ expEvaluator.addExpressionFunction("eval", (ctx, ...args) => {
4769
+ return ctx.evaluate(...args);
4770
+ });
4771
+ });
4772
+ }
4773
+ }
4774
+
4231
4775
  const NOT_STARTED_STATE = {
4232
4776
  ref: Symbol("not-started"),
4233
4777
  status: "not-started"
@@ -4272,8 +4816,8 @@ var __async = (__this, __arguments, generator) => {
4272
4816
  step((generator = generator.apply(__this, __arguments)).next());
4273
4817
  });
4274
4818
  };
4275
- const PLAYER_VERSION = "0.3.1-next.0";
4276
- const COMMIT = "b51603be07572111ca68e73d1b710ed2d0aa9412";
4819
+ const PLAYER_VERSION = "0.3.1";
4820
+ const COMMIT = "e8392cd5df3c84fb9c68daf149ea88c593ce0428";
4277
4821
  const _Player = class {
4278
4822
  constructor(config) {
4279
4823
  this.logger = new TapableLogger();
@@ -4294,14 +4838,15 @@ const _Player = class {
4294
4838
  resolveFlowContent: new tapableTs.SyncWaterfallHook()
4295
4839
  };
4296
4840
  var _a;
4297
- const initialPlugins = [];
4298
- const flowExpPlugin = new FlowExpPlugin();
4299
- initialPlugins.push(flowExpPlugin);
4300
4841
  if (config == null ? void 0 : config.logger) {
4301
4842
  this.logger.addHandler(config.logger);
4302
4843
  }
4303
4844
  this.config = config || {};
4304
- this.config.plugins = [...this.config.plugins || [], ...initialPlugins];
4845
+ this.config.plugins = [
4846
+ new DefaultExpPlugin(),
4847
+ ...this.config.plugins || [],
4848
+ new FlowExpPlugin()
4849
+ ];
4305
4850
  (_a = this.config.plugins) == null ? void 0 : _a.forEach((plugin) => {
4306
4851
  plugin.apply(this);
4307
4852
  });
@@ -4392,25 +4937,27 @@ const _Player = class {
4392
4937
  flowResultDeferred.reject(e);
4393
4938
  return true;
4394
4939
  });
4395
- function resolveStrings(val) {
4940
+ function resolveStrings(val, formatted) {
4396
4941
  return resolveDataRefs(val, {
4397
4942
  model: dataController,
4398
- evaluate: expressionEvaluator.evaluate
4943
+ evaluate: expressionEvaluator.evaluate,
4944
+ formatted
4399
4945
  });
4400
4946
  }
4401
4947
  flowController.hooks.flow.tap("player", (flow) => {
4402
4948
  flow.hooks.beforeTransition.tap("player", (state, transitionVal) => {
4403
- if (state.onEnd && (state.transitions[transitionVal] || state.transitions["*"])) {
4949
+ const computedTransitionVal = state.transitions[transitionVal] ? transitionVal : "*";
4950
+ if (state.onEnd && state.transitions[computedTransitionVal]) {
4404
4951
  if (typeof state.onEnd === "object" && "exp" in state.onEnd) {
4405
4952
  expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(state.onEnd.exp);
4406
4953
  } else {
4407
4954
  expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(state.onEnd);
4408
4955
  }
4409
4956
  }
4410
- if (!("transitions" in state) || !state.transitions[transitionVal]) {
4957
+ if (!("transitions" in state) || !state.transitions[computedTransitionVal]) {
4411
4958
  return state;
4412
4959
  }
4413
- return timm.setIn(state, ["transitions", transitionVal], resolveStrings(state.transitions[transitionVal]));
4960
+ return timm.setIn(state, ["transitions", computedTransitionVal], resolveStrings(state.transitions[computedTransitionVal]));
4414
4961
  });
4415
4962
  flow.hooks.skipTransition.tap("validation", (currentState) => {
4416
4963
  var _a;
@@ -4430,16 +4977,21 @@ const _Player = class {
4430
4977
  newState = timm.setIn(state, ["ref"], resolveStrings(state.ref));
4431
4978
  }
4432
4979
  if ("param" in state) {
4433
- newState = timm.setIn(state, ["param"], resolveStrings(state.param));
4980
+ newState = timm.setIn(state, ["param"], resolveStrings(state.param, false));
4434
4981
  }
4435
4982
  return newState;
4436
4983
  });
4437
4984
  flow.hooks.transition.tap("player", (_oldState, newState) => {
4438
- if (newState.value.state_type === "ACTION") {
4439
- const { exp } = newState.value;
4440
- queueMicrotask__default["default"](() => {
4441
- flowController == null ? void 0 : flowController.transition(String(expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(exp)));
4442
- });
4985
+ if (newState.value.state_type !== "VIEW") {
4986
+ validationController.reset();
4987
+ }
4988
+ });
4989
+ flow.hooks.afterTransition.tap("player", (flowInstance) => {
4990
+ var _a;
4991
+ const value = (_a = flowInstance.currentState) == null ? void 0 : _a.value;
4992
+ if (value && value.state_type === "ACTION") {
4993
+ const { exp } = value;
4994
+ flowController == null ? void 0 : flowController.transition(String(expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(exp)));
4443
4995
  }
4444
4996
  expressionEvaluator.reset();
4445
4997
  });
@@ -4457,6 +5009,11 @@ const _Player = class {
4457
5009
  parseBinding,
4458
5010
  transition: flowController.transition,
4459
5011
  model: dataController,
5012
+ utils: {
5013
+ findPlugin: (pluginSymbol) => {
5014
+ return this.findPlugin(pluginSymbol);
5015
+ }
5016
+ },
4460
5017
  logger: this.logger,
4461
5018
  flowController,
4462
5019
  schema,
@@ -4470,23 +5027,19 @@ const _Player = class {
4470
5027
  },
4471
5028
  validation: __spreadProps(__spreadValues({}, validationController.forView(parseBinding)), {
4472
5029
  type: (b) => schema.getType(parseBinding(b))
4473
- })
5030
+ }),
5031
+ constants: this.constantsController
4474
5032
  });
4475
5033
  viewController.hooks.view.tap("player", (view) => {
4476
5034
  validationController.onView(view);
4477
5035
  this.hooks.view.call(view);
4478
5036
  });
4479
5037
  this.hooks.viewController.call(viewController);
4480
- const formatFunction = (ctx, value, formatName) => {
4481
- var _a, _b;
4482
- return (_b = (_a = schema.getFormatterForType({ type: formatName })) == null ? void 0 : _a.format(value)) != null ? _b : value;
4483
- };
4484
- expressionEvaluator.addExpressionFunction("format", formatFunction);
4485
5038
  return {
4486
5039
  start: () => {
4487
5040
  flowController.start().then((endState) => {
4488
5041
  const flowResult = {
4489
- endState: resolveStrings(endState),
5042
+ endState: resolveStrings(endState, false),
4490
5043
  data: dataController.serialize()
4491
5044
  };
4492
5045
  return flowResult;
@@ -4539,7 +5092,9 @@ const _Player = class {
4539
5092
  ref,
4540
5093
  status: "completed",
4541
5094
  flow: state.flow,
4542
- dataModel: state.controllers.data.getModel()
5095
+ controllers: {
5096
+ data: state.controllers.data.makeReadOnly()
5097
+ }
4543
5098
  };
4544
5099
  return maybeUpdateState(__spreadValues(__spreadValues({}, yield state.flowResult), endProps));
4545
5100
  } catch (error) {
@@ -4563,6 +5118,7 @@ Player.info = {
4563
5118
 
4564
5119
  exports.ApplicabilityPlugin = ApplicabilityPlugin;
4565
5120
  exports.AssetTransformCorePlugin = AssetTransformCorePlugin;
5121
+ exports.BINDING_BRACKETS_REGEX = BINDING_BRACKETS_REGEX;
4566
5122
  exports.BindingInstance = BindingInstance;
4567
5123
  exports.BindingParser = BindingParser;
4568
5124
  exports.Builder = Builder;
@@ -4590,12 +5146,15 @@ exports.Player = Player;
4590
5146
  exports.ProxyLogger = ProxyLogger;
4591
5147
  exports.ROOT_BINDING = ROOT_BINDING;
4592
5148
  exports.Resolver = Resolver;
5149
+ exports.SCHEMA_VALIDATION_PROVIDER_NAME = SCHEMA_VALIDATION_PROVIDER_NAME;
4593
5150
  exports.SIMPLE_BINDING_REGEX = SIMPLE_BINDING_REGEX;
4594
5151
  exports.SchemaController = SchemaController;
4595
5152
  exports.StringResolverPlugin = StringResolverPlugin;
4596
5153
  exports.SwitchPlugin = SwitchPlugin;
4597
5154
  exports.TapableLogger = TapableLogger;
4598
5155
  exports.TemplatePlugin = TemplatePlugin;
5156
+ exports.VALIDATION_PROVIDER_NAME_SYMBOL = VALIDATION_PROVIDER_NAME_SYMBOL;
5157
+ exports.VIEW_VALIDATION_PROVIDER_NAME = VIEW_VALIDATION_PROVIDER_NAME;
4599
5158
  exports.ValidationBindingTrackerViewPlugin = ValidationBindingTrackerViewPlugin;
4600
5159
  exports.ValidationController = ValidationController;
4601
5160
  exports.ValidationMiddleware = ValidationMiddleware;
@@ -4604,13 +5163,17 @@ exports.ViewController = ViewController;
4604
5163
  exports.ViewInstance = ViewInstance;
4605
5164
  exports.caresAboutDataChanges = caresAboutDataChanges;
4606
5165
  exports.constructModelForPipeline = constructModelForPipeline;
5166
+ exports.findClosestNodeAtPosition = findClosestNodeAtPosition;
4607
5167
  exports.findInArray = findInArray;
4608
5168
  exports.findNextExp = findNextExp;
4609
5169
  exports.getBindingSegments = getBindingSegments;
4610
5170
  exports.isBinding = isBinding;
4611
5171
  exports.isExpressionNode = isExpressionNode;
5172
+ exports.isObjectExpression = isObjectExpression;
4612
5173
  exports.maybeConvertToNum = maybeConvertToNum;
4613
5174
  exports.parse = parse;
5175
+ exports.parseExpression = parseExpression;
5176
+ exports.removeBindingAndChildrenFromMap = removeBindingAndChildrenFromMap;
4614
5177
  exports.resolveDataRefs = resolveDataRefs;
4615
5178
  exports.resolveDataRefsInString = resolveDataRefsInString;
4616
5179
  exports.resolveExpressionsInString = resolveExpressionsInString;