@player-ui/player 0.3.1-next.1 → 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.esm.js CHANGED
@@ -1,11 +1,11 @@
1
1
  export * from '@player-ui/types';
2
2
  import { SyncBailHook, SyncWaterfallHook, SyncHook } from 'tapable-ts';
3
- import NestedError from 'nested-error-stacks';
3
+ import { NestedError } from 'ts-nested-error';
4
4
  import flatten$1 from 'arr-flatten';
5
5
  import P from 'parsimmon';
6
6
  import { Grammars } from 'ebnf';
7
7
  import get from 'dlv';
8
- import { setIn, addLast, set, omit, removeAt } from 'timm';
8
+ import { setIn, removeAt, omit, clone, addLast, set } from 'timm';
9
9
  import { dequal } from 'dequal';
10
10
  import defer from 'p-defer';
11
11
  import queueMicrotask from 'queue-microtask';
@@ -93,7 +93,8 @@ const isIdentifierChar = (char) => {
93
93
  return false;
94
94
  }
95
95
  const charCode = char.charCodeAt(0);
96
- return charCode >= 48 && charCode <= 57 || charCode >= 65 && charCode <= 90 || charCode >= 97 && charCode <= 122 || charCode === 95 || charCode === 45 || charCode === 64;
96
+ 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;
97
+ return !matches;
97
98
  };
98
99
  const parse$1 = (path) => {
99
100
  let index = 1;
@@ -457,6 +458,8 @@ var __spreadValues$d = (a, b) => {
457
458
  return a;
458
459
  };
459
460
  const SIMPLE_BINDING_REGEX = /^[\w\-@]+(\.[\w\-@]+)*$/;
461
+ const BINDING_BRACKETS_REGEX = /[\s()*=`{}'"[\]]/;
462
+ const LAZY_BINDING_REGEX = /^[^.]+(\..+)*$/;
460
463
  const DEFAULT_OPTIONS = {
461
464
  get: () => {
462
465
  throw new Error("Not Implemented");
@@ -481,7 +484,7 @@ class BindingParser {
481
484
  }
482
485
  normalizePath(path, resolveOptions) {
483
486
  var _a, _b;
484
- if (path.match(SIMPLE_BINDING_REGEX) && this.hooks.skipOptimization.call(path) !== true) {
487
+ if (!BINDING_BRACKETS_REGEX.test(path) && LAZY_BINDING_REGEX.test(path) && this.hooks.skipOptimization.call(path) !== true) {
485
488
  return { path: path.split("."), updates: void 0 };
486
489
  }
487
490
  const ast = (_a = this.parseCache[path]) != null ? _a : parse$1(path);
@@ -542,7 +545,7 @@ class BindingParser {
542
545
  updates = __spreadValues$d(__spreadValues$d({}, updates), normalized.updates);
543
546
  }
544
547
  const updateKeys = Object.keys(updates);
545
- if (updateKeys.length > 0) {
548
+ if (!options.readOnly && updateKeys.length > 0) {
546
549
  const updateTransaction = updateKeys.map((updatedBinding) => [
547
550
  this.parse(updatedBinding),
548
551
  updates[updatedBinding]
@@ -638,6 +641,10 @@ class DependencyMiddleware extends DependencyTracker {
638
641
  this.addReadDep(binding);
639
642
  return next == null ? void 0 : next.get(binding, options);
640
643
  }
644
+ delete(binding, options, next) {
645
+ this.addWriteDep(binding);
646
+ return next == null ? void 0 : next.delete(binding, options);
647
+ }
641
648
  }
642
649
  class DependencyModel extends DependencyTracker {
643
650
  constructor(rootModel) {
@@ -654,6 +661,10 @@ class DependencyModel extends DependencyTracker {
654
661
  this.addReadDep(binding);
655
662
  return this.rootModel.get(binding, options);
656
663
  }
664
+ delete(binding, options) {
665
+ this.addWriteDep(binding);
666
+ return this.rootModel.delete(binding, options);
667
+ }
657
668
  }
658
669
 
659
670
  class NOOPDataModel {
@@ -663,15 +674,18 @@ class NOOPDataModel {
663
674
  set() {
664
675
  return [];
665
676
  }
677
+ delete() {
678
+ }
666
679
  }
667
680
  const NOOP_MODEL = new NOOPDataModel();
668
681
 
669
682
  const ROOT_BINDING = new BindingInstance([]);
670
683
  function withParser(model, parseBinding) {
671
- function maybeParse(binding) {
684
+ function maybeParse(binding, readOnly) {
672
685
  const parsed = isBinding(binding) ? binding : parseBinding(binding, {
673
686
  get: model.get,
674
- set: model.set
687
+ set: model.set,
688
+ readOnly
675
689
  });
676
690
  if (!parsed) {
677
691
  throw new Error("Unable to parse binding");
@@ -680,10 +694,13 @@ function withParser(model, parseBinding) {
680
694
  }
681
695
  return {
682
696
  get(binding, options) {
683
- return model.get(maybeParse(binding), options);
697
+ return model.get(maybeParse(binding, true), options);
684
698
  },
685
699
  set(transaction, options) {
686
- return model.set(transaction.map(([key, val]) => [maybeParse(key), val]), options);
700
+ return model.set(transaction.map(([key, val]) => [maybeParse(key, false), val]), options);
701
+ },
702
+ delete(binding, options) {
703
+ return model.delete(maybeParse(binding, false), options);
687
704
  }
688
705
  };
689
706
  }
@@ -692,8 +709,27 @@ function toModel(middleware, defaultOptions, next) {
692
709
  return middleware;
693
710
  }
694
711
  return {
695
- get: (binding, options) => middleware.get(binding, options != null ? options : defaultOptions, next),
696
- set: (transaction, options) => middleware.set(transaction, options != null ? options : defaultOptions, next)
712
+ get: (binding, options) => {
713
+ const resolvedOptions = options != null ? options : defaultOptions;
714
+ if (middleware.get) {
715
+ return middleware.get(binding, resolvedOptions, next);
716
+ }
717
+ return next == null ? void 0 : next.get(binding, resolvedOptions);
718
+ },
719
+ set: (transaction, options) => {
720
+ const resolvedOptions = options != null ? options : defaultOptions;
721
+ if (middleware.set) {
722
+ return middleware.set(transaction, resolvedOptions, next);
723
+ }
724
+ return next == null ? void 0 : next.set(transaction, resolvedOptions);
725
+ },
726
+ delete: (binding, options) => {
727
+ const resolvedOptions = options != null ? options : defaultOptions;
728
+ if (middleware.delete) {
729
+ return middleware.delete(binding, resolvedOptions, next);
730
+ }
731
+ return next == null ? void 0 : next.delete(binding, resolvedOptions);
732
+ }
697
733
  };
698
734
  }
699
735
  function constructModelForPipeline(pipeline) {
@@ -701,7 +737,7 @@ function constructModelForPipeline(pipeline) {
701
737
  return NOOP_MODEL;
702
738
  }
703
739
  if (pipeline.length === 1) {
704
- return pipeline[0];
740
+ return toModel(pipeline[0]);
705
741
  }
706
742
  function createModelWithOptions(options) {
707
743
  var _a;
@@ -716,6 +752,10 @@ function constructModelForPipeline(pipeline) {
716
752
  set: (transaction, options) => {
717
753
  var _a;
718
754
  return (_a = createModelWithOptions(options)) == null ? void 0 : _a.set(transaction, options);
755
+ },
756
+ delete: (binding, options) => {
757
+ var _a;
758
+ return (_a = createModelWithOptions(options)) == null ? void 0 : _a.delete(binding, options);
719
759
  }
720
760
  };
721
761
  }
@@ -752,6 +792,9 @@ class PipelinedDataModel {
752
792
  get(binding, options) {
753
793
  return this.effectiveDataModel.get(binding, options);
754
794
  }
795
+ delete(binding, options) {
796
+ return this.effectiveDataModel.delete(binding, options);
797
+ }
755
798
  }
756
799
 
757
800
  class LocalModel {
@@ -778,11 +821,24 @@ class LocalModel {
778
821
  });
779
822
  return effectiveOperations;
780
823
  }
824
+ delete(binding) {
825
+ const parentBinding = binding.parent();
826
+ if (parentBinding) {
827
+ const parentValue = this.get(parentBinding);
828
+ if (parentValue !== void 0) {
829
+ if (Array.isArray(parentValue)) {
830
+ this.model = setIn(this.model, parentBinding.asArray(), removeAt(parentValue, binding.key()));
831
+ } else {
832
+ this.model = setIn(this.model, parentBinding.asArray(), omit(parentValue, binding.key()));
833
+ }
834
+ }
835
+ }
836
+ }
781
837
  }
782
838
 
783
839
  const ExpNodeOpaqueIdentifier = Symbol("Expression Node ID");
784
840
  function isExpressionNode(x) {
785
- return typeof x === "object" && x.__id === ExpNodeOpaqueIdentifier;
841
+ return typeof x === "object" && x !== null && !Array.isArray(x) && x.__id === ExpNodeOpaqueIdentifier;
786
842
  }
787
843
 
788
844
  const PERIOD_CODE = 46;
@@ -834,6 +890,15 @@ function throwError(message, index) {
834
890
  err.description = message;
835
891
  throw err;
836
892
  }
893
+ function createSpanningLocation(start, end) {
894
+ if (!start || !end) {
895
+ return;
896
+ }
897
+ return {
898
+ start: start.start,
899
+ end: end.end
900
+ };
901
+ }
837
902
  function getMaxKeyLen(obj) {
838
903
  let maxLen = 0;
839
904
  Object.keys(obj).forEach((key) => {
@@ -855,7 +920,7 @@ const thisStr = "this";
855
920
  function binaryPrecedence(opVal) {
856
921
  return binaryOps[opVal] || 0;
857
922
  }
858
- function createBinaryExpression(operator, left, right) {
923
+ function createBinaryExpression(operator, left, right, location) {
859
924
  let type;
860
925
  if (operator === "||" || operator === "&&") {
861
926
  type = "LogicalExpression";
@@ -871,7 +936,8 @@ function createBinaryExpression(operator, left, right) {
871
936
  type,
872
937
  operator,
873
938
  left,
874
- right
939
+ right,
940
+ location
875
941
  };
876
942
  }
877
943
  function isDecimalDigit(ch) {
@@ -886,11 +952,23 @@ function isIdentifierPart(ch) {
886
952
  function isModelRefStart(ch0, ch1) {
887
953
  return ch0 === OCURL_CODE && ch1 === OCURL_CODE;
888
954
  }
889
- function parseExpression(expr) {
955
+ function parseExpression(expr, options) {
956
+ var _a;
957
+ const strictMode = (_a = options == null ? void 0 : options.strict) != null ? _a : true;
890
958
  const charAtFunc = expr.charAt;
891
959
  const charCodeAtFunc = expr.charCodeAt;
892
960
  const { length } = expr;
893
961
  let index = 0;
962
+ const getLocation = (startChar) => {
963
+ return {
964
+ start: {
965
+ character: startChar
966
+ },
967
+ end: {
968
+ character: index
969
+ }
970
+ };
971
+ };
894
972
  function exprI(i) {
895
973
  return charAtFunc.call(expr, i);
896
974
  }
@@ -904,6 +982,7 @@ function parseExpression(expr) {
904
982
  let key;
905
983
  let value;
906
984
  let chCode;
985
+ const startCharIndex = index;
907
986
  ++index;
908
987
  while (index < length) {
909
988
  gobbleSpaces();
@@ -949,7 +1028,8 @@ function parseExpression(expr) {
949
1028
  return {
950
1029
  __id: ExpNodeOpaqueIdentifier,
951
1030
  type: "Object",
952
- attributes
1031
+ attributes,
1032
+ location: getLocation(startCharIndex)
953
1033
  };
954
1034
  }
955
1035
  function gobbleSpaces() {
@@ -961,6 +1041,7 @@ function parseExpression(expr) {
961
1041
  function gobbleExpression() {
962
1042
  const test = gobbleBinaryExpression();
963
1043
  gobbleSpaces();
1044
+ const startCharIndex = index;
964
1045
  if (index < length && exprICode(index) === QUMARK_CODE) {
965
1046
  index++;
966
1047
  const consequent = gobbleExpression();
@@ -979,7 +1060,8 @@ function parseExpression(expr) {
979
1060
  type: "ConditionalExpression",
980
1061
  test,
981
1062
  consequent,
982
- alternate
1063
+ alternate,
1064
+ location: getLocation(startCharIndex)
983
1065
  };
984
1066
  }
985
1067
  throwError("Expected :", index);
@@ -1025,7 +1107,7 @@ function parseExpression(expr) {
1025
1107
  right = stack.pop();
1026
1108
  biop = stack.pop().value;
1027
1109
  left = stack.pop();
1028
- node = createBinaryExpression(biop, left, right);
1110
+ node = createBinaryExpression(biop, left, right, createSpanningLocation(left.location, right.location));
1029
1111
  stack.push(node);
1030
1112
  }
1031
1113
  node = gobbleToken();
@@ -1038,7 +1120,7 @@ function parseExpression(expr) {
1038
1120
  i = stack.length - 1;
1039
1121
  node = stack[i];
1040
1122
  while (i > 1) {
1041
- node = createBinaryExpression(stack[i - 1].value, stack[i - 2], node);
1123
+ node = createBinaryExpression(stack[i - 1].value, stack[i - 2], node, createSpanningLocation(stack[i - 2].location, node.location));
1042
1124
  i -= 2;
1043
1125
  }
1044
1126
  return node;
@@ -1046,6 +1128,7 @@ function parseExpression(expr) {
1046
1128
  function gobbleToken() {
1047
1129
  gobbleSpaces();
1048
1130
  const ch = exprICode(index);
1131
+ const startCharIndex = index;
1049
1132
  if (isDecimalDigit(ch) || ch === PERIOD_CODE) {
1050
1133
  return gobbleNumericLiteral();
1051
1134
  }
@@ -1074,7 +1157,8 @@ function parseExpression(expr) {
1074
1157
  type: "UnaryExpression",
1075
1158
  operator: toCheck,
1076
1159
  argument: gobbleToken(),
1077
- prefix: true
1160
+ prefix: true,
1161
+ location: getLocation(startCharIndex)
1078
1162
  };
1079
1163
  }
1080
1164
  toCheck = toCheck.substr(0, --tcLen);
@@ -1083,6 +1167,7 @@ function parseExpression(expr) {
1083
1167
  }
1084
1168
  function gobbleNumericLiteral() {
1085
1169
  let num = "";
1170
+ const startCharIndex = index;
1086
1171
  while (isDecimalDigit(exprICode(index))) {
1087
1172
  num += exprI(index++);
1088
1173
  }
@@ -1116,13 +1201,15 @@ function parseExpression(expr) {
1116
1201
  __id: ExpNodeOpaqueIdentifier,
1117
1202
  type: "Literal",
1118
1203
  value: parseFloat(num),
1119
- raw: num
1204
+ raw: num,
1205
+ location: getLocation(startCharIndex)
1120
1206
  };
1121
1207
  }
1122
1208
  function gobbleStringLiteral() {
1123
1209
  const quote = exprI(index++);
1124
1210
  let str = "";
1125
1211
  let closed = false;
1212
+ const startCharIndex = index;
1126
1213
  while (index < length) {
1127
1214
  let ch = exprI(index++);
1128
1215
  if (ch === quote) {
@@ -1162,13 +1249,15 @@ function parseExpression(expr) {
1162
1249
  __id: ExpNodeOpaqueIdentifier,
1163
1250
  type: "Literal",
1164
1251
  value: str,
1165
- raw: `${quote}${str}${quote}`
1252
+ raw: `${quote}${str}${quote}`,
1253
+ location: getLocation(startCharIndex)
1166
1254
  };
1167
1255
  }
1168
1256
  function gobbleModelRef() {
1169
1257
  let str = "";
1170
1258
  let closed = false;
1171
1259
  let openBraceCount = 1;
1260
+ const startCharIndex = index;
1172
1261
  index += 2;
1173
1262
  while (index < length) {
1174
1263
  const ch = exprI(index++);
@@ -1194,7 +1283,8 @@ function parseExpression(expr) {
1194
1283
  return {
1195
1284
  __id: ExpNodeOpaqueIdentifier,
1196
1285
  type: "ModelRef",
1197
- ref: str
1286
+ ref: str,
1287
+ location: getLocation(startCharIndex)
1198
1288
  };
1199
1289
  }
1200
1290
  function gobbleIdentifier() {
@@ -1219,19 +1309,22 @@ function parseExpression(expr) {
1219
1309
  __id: ExpNodeOpaqueIdentifier,
1220
1310
  type: "Literal",
1221
1311
  value: literals[identifier],
1222
- raw: identifier
1312
+ raw: identifier,
1313
+ location: getLocation(start)
1223
1314
  };
1224
1315
  }
1225
1316
  if (identifier === thisStr) {
1226
1317
  return {
1227
1318
  __id: ExpNodeOpaqueIdentifier,
1228
- type: "ThisExpression"
1319
+ type: "ThisExpression",
1320
+ location: getLocation(start)
1229
1321
  };
1230
1322
  }
1231
1323
  return {
1232
1324
  __id: ExpNodeOpaqueIdentifier,
1233
1325
  type: "Identifier",
1234
- name: identifier
1326
+ name: identifier,
1327
+ location: getLocation(start)
1235
1328
  };
1236
1329
  }
1237
1330
  function gobbleArguments(termination) {
@@ -1255,11 +1348,15 @@ function parseExpression(expr) {
1255
1348
  }
1256
1349
  args.push(node);
1257
1350
  }
1351
+ if (charIndex !== termination) {
1352
+ throwError(`Expected ${String.fromCharCode(termination)}`, index);
1353
+ }
1258
1354
  return args;
1259
1355
  }
1260
1356
  function gobbleVariable() {
1261
1357
  let charIndex = exprICode(index);
1262
1358
  let node = charIndex === OPAREN_CODE ? gobbleGroup() : gobbleIdentifier();
1359
+ const startCharIndex = index;
1263
1360
  gobbleSpaces();
1264
1361
  charIndex = exprICode(index);
1265
1362
  while (charIndex === PERIOD_CODE || charIndex === OBRACK_CODE || charIndex === OPAREN_CODE) {
@@ -1271,7 +1368,8 @@ function parseExpression(expr) {
1271
1368
  type: "MemberExpression",
1272
1369
  computed: false,
1273
1370
  object: node,
1274
- property: gobbleIdentifier()
1371
+ property: gobbleIdentifier(),
1372
+ location: getLocation(startCharIndex)
1275
1373
  };
1276
1374
  } else if (charIndex === OBRACK_CODE) {
1277
1375
  node = {
@@ -1279,7 +1377,8 @@ function parseExpression(expr) {
1279
1377
  type: "MemberExpression",
1280
1378
  computed: true,
1281
1379
  object: node,
1282
- property: gobbleExpression()
1380
+ property: gobbleExpression(),
1381
+ location: getLocation(startCharIndex)
1283
1382
  };
1284
1383
  gobbleSpaces();
1285
1384
  charIndex = exprICode(index);
@@ -1292,7 +1391,8 @@ function parseExpression(expr) {
1292
1391
  __id: ExpNodeOpaqueIdentifier,
1293
1392
  type: "CallExpression",
1294
1393
  args: gobbleArguments(CPAREN_CODE),
1295
- callTarget: node
1394
+ callTarget: node,
1395
+ location: getLocation(startCharIndex)
1296
1396
  };
1297
1397
  }
1298
1398
  gobbleSpaces();
@@ -1311,35 +1411,51 @@ function parseExpression(expr) {
1311
1411
  throwError("Unclosed (", index);
1312
1412
  }
1313
1413
  function gobbleArray() {
1414
+ const startCharIndex = index;
1314
1415
  index++;
1315
1416
  return {
1316
1417
  __id: ExpNodeOpaqueIdentifier,
1317
1418
  type: "ArrayExpression",
1318
- elements: gobbleArguments(CBRACK_CODE)
1419
+ elements: gobbleArguments(CBRACK_CODE),
1420
+ location: getLocation(startCharIndex)
1319
1421
  };
1320
1422
  }
1321
1423
  const nodes = [];
1322
- while (index < length) {
1323
- const chIndex = exprICode(index);
1324
- if (chIndex === SEMCOL_CODE || chIndex === COMMA_CODE) {
1325
- index++;
1326
- continue;
1424
+ try {
1425
+ while (index < length) {
1426
+ const chIndex = exprICode(index);
1427
+ if (chIndex === SEMCOL_CODE || chIndex === COMMA_CODE) {
1428
+ index++;
1429
+ continue;
1430
+ }
1431
+ const node = gobbleExpression();
1432
+ if (node) {
1433
+ nodes.push(node);
1434
+ } else if (index < length) {
1435
+ throwError(`Unexpected "${exprI(index)}"`, index);
1436
+ }
1327
1437
  }
1328
- const node = gobbleExpression();
1329
- if (node) {
1330
- nodes.push(node);
1331
- } else if (index < length) {
1332
- throwError(`Unexpected "${exprI(index)}"`, index);
1438
+ if (nodes.length === 1) {
1439
+ return nodes[0];
1333
1440
  }
1441
+ return {
1442
+ __id: ExpNodeOpaqueIdentifier,
1443
+ type: "Compound",
1444
+ body: nodes,
1445
+ location: getLocation(0)
1446
+ };
1447
+ } catch (e) {
1448
+ if (strictMode || !(e instanceof Error)) {
1449
+ throw e;
1450
+ }
1451
+ return {
1452
+ __id: ExpNodeOpaqueIdentifier,
1453
+ type: "Compound",
1454
+ body: nodes,
1455
+ location: getLocation(0),
1456
+ error: e
1457
+ };
1334
1458
  }
1335
- if (nodes.length === 1) {
1336
- return nodes[0];
1337
- }
1338
- return {
1339
- __id: ExpNodeOpaqueIdentifier,
1340
- type: "Compound",
1341
- body: nodes
1342
- };
1343
1459
  }
1344
1460
 
1345
1461
  const setDataVal = (_context, binding, value) => {
@@ -1349,16 +1465,108 @@ const getDataVal = (_context, binding) => {
1349
1465
  return _context.model.get(binding);
1350
1466
  };
1351
1467
  const deleteDataVal = (_context, binding) => {
1352
- return _context.model.set([[binding, void 0]]);
1468
+ return _context.model.delete(binding);
1353
1469
  };
1470
+ const conditional = (ctx, condition, ifTrue, ifFalse) => {
1471
+ const resolution = ctx.evaluate(condition);
1472
+ if (resolution) {
1473
+ return ctx.evaluate(ifTrue);
1474
+ }
1475
+ if (ifFalse) {
1476
+ return ctx.evaluate(ifFalse);
1477
+ }
1478
+ return null;
1479
+ };
1480
+ conditional.resolveParams = false;
1354
1481
 
1355
1482
  var DEFAULT_EXPRESSION_HANDLERS = /*#__PURE__*/Object.freeze({
1356
1483
  __proto__: null,
1357
1484
  setDataVal: setDataVal,
1358
1485
  getDataVal: getDataVal,
1359
- deleteDataVal: deleteDataVal
1486
+ deleteDataVal: deleteDataVal,
1487
+ conditional: conditional
1360
1488
  });
1361
1489
 
1490
+ function withoutContext(fn) {
1491
+ return (_context, ...args) => fn(...args);
1492
+ }
1493
+ function isInRange(position, location) {
1494
+ return position.character >= location.start.character && position.character <= location.end.character;
1495
+ }
1496
+ function findClosestNodeAtPosition(node, position) {
1497
+ var _a, _b, _c, _d, _e;
1498
+ switch (node.type) {
1499
+ case "Modification":
1500
+ case "Assignment":
1501
+ case "LogicalExpression":
1502
+ case "BinaryExpression": {
1503
+ const check = (_a = findClosestNodeAtPosition(node.left, position)) != null ? _a : findClosestNodeAtPosition(node.right, position);
1504
+ if (check) {
1505
+ return check;
1506
+ }
1507
+ break;
1508
+ }
1509
+ case "UnaryExpression": {
1510
+ const checkArg = findClosestNodeAtPosition(node.argument, position);
1511
+ if (checkArg) {
1512
+ return checkArg;
1513
+ }
1514
+ break;
1515
+ }
1516
+ case "MemberExpression": {
1517
+ const checkObject = (_b = findClosestNodeAtPosition(node.object, position)) != null ? _b : findClosestNodeAtPosition(node.property, position);
1518
+ if (checkObject) {
1519
+ return checkObject;
1520
+ }
1521
+ break;
1522
+ }
1523
+ case "ConditionalExpression": {
1524
+ const checkObject = (_d = (_c = findClosestNodeAtPosition(node.test, position)) != null ? _c : findClosestNodeAtPosition(node.consequent, position)) != null ? _d : findClosestNodeAtPosition(node.alternate, position);
1525
+ if (checkObject) {
1526
+ return checkObject;
1527
+ }
1528
+ break;
1529
+ }
1530
+ case "ArrayExpression":
1531
+ case "Compound": {
1532
+ const elements = node.type === "ArrayExpression" ? node.elements : node.body;
1533
+ const anyElements = elements.find((e) => findClosestNodeAtPosition(e, position));
1534
+ if (anyElements) {
1535
+ return anyElements;
1536
+ }
1537
+ break;
1538
+ }
1539
+ case "Object": {
1540
+ const checkObject = node.attributes.reduce((found, next) => {
1541
+ var _a2;
1542
+ return (_a2 = found != null ? found : findClosestNodeAtPosition(next.key, position)) != null ? _a2 : findClosestNodeAtPosition(next.value, position);
1543
+ }, void 0);
1544
+ if (checkObject) {
1545
+ return checkObject;
1546
+ }
1547
+ break;
1548
+ }
1549
+ case "CallExpression": {
1550
+ const anyArgs = (_e = node.args.find((arg) => {
1551
+ return findClosestNodeAtPosition(arg, position);
1552
+ })) != null ? _e : findClosestNodeAtPosition(node.callTarget, position);
1553
+ if (anyArgs) {
1554
+ return anyArgs;
1555
+ }
1556
+ break;
1557
+ }
1558
+ }
1559
+ if (node.location && isInRange(position, node.location)) {
1560
+ return node;
1561
+ }
1562
+ }
1563
+ function isObjectExpression(expr) {
1564
+ if (isExpressionNode(expr)) {
1565
+ return false;
1566
+ }
1567
+ return typeof expr === "object" && expr !== null && !Array.isArray(expr) && "value" in expr;
1568
+ }
1569
+
1362
1570
  var __defProp$c = Object.defineProperty;
1363
1571
  var __defProps$a = Object.defineProperties;
1364
1572
  var __getOwnPropDescs$a = Object.getOwnPropertyDescriptors;
@@ -1419,6 +1627,8 @@ class ExpressionEvaluator {
1419
1627
  this.vars = {};
1420
1628
  this.hooks = {
1421
1629
  resolve: new SyncWaterfallHook(),
1630
+ resolveOptions: new SyncWaterfallHook(),
1631
+ beforeEvaluate: new SyncWaterfallHook(),
1422
1632
  onError: new SyncBailHook()
1423
1633
  };
1424
1634
  this.expressionsCache = new Map();
@@ -1437,21 +1647,25 @@ class ExpressionEvaluator {
1437
1647
  reset() {
1438
1648
  this.expressionsCache.clear();
1439
1649
  }
1440
- evaluate(expression, options) {
1441
- const opts = __spreadProps$a(__spreadValues$c(__spreadValues$c({}, this.defaultHookOptions), options), {
1442
- resolveNode: (node) => this._execAST(node, opts)
1443
- });
1650
+ evaluate(expr, options) {
1651
+ var _a;
1652
+ const resolvedOpts = this.hooks.resolveOptions.call(__spreadProps$a(__spreadValues$c(__spreadValues$c({}, this.defaultHookOptions), options), {
1653
+ resolveNode: (node) => this._execAST(node, resolvedOpts)
1654
+ }));
1655
+ let expression = (_a = this.hooks.beforeEvaluate.call(expr, resolvedOpts)) != null ? _a : expr;
1656
+ while (isObjectExpression(expression)) {
1657
+ expression = expression.value;
1658
+ }
1444
1659
  if (typeof expression === "number" || typeof expression === "boolean" || expression === void 0 || expression === null) {
1445
1660
  return expression;
1446
1661
  }
1447
1662
  if (isExpressionNode(expression)) {
1448
- return this._execAST(expression, opts);
1663
+ return this._execAST(expression, resolvedOpts);
1449
1664
  }
1450
- if (typeof expression === "object") {
1451
- const values = Array.isArray(expression) ? expression : Object.values(expression);
1452
- return values.reduce((_nothing, exp) => this.evaluate(exp, options), null);
1665
+ if (Array.isArray(expression)) {
1666
+ return expression.reduce((_nothing, exp) => this.evaluate(exp, options), null);
1453
1667
  }
1454
- return this._execString(String(expression), opts);
1668
+ return this._execString(String(expression), resolvedOpts);
1455
1669
  }
1456
1670
  addExpressionFunction(name, handler) {
1457
1671
  this.operators.expressions.set(name, handler);
@@ -1489,7 +1703,7 @@ class ExpressionEvaluator {
1489
1703
  this.expressionsCache.set(matchedExp, expAST);
1490
1704
  return this._execAST(expAST, options);
1491
1705
  } catch (e) {
1492
- if (!this.hooks.onError.call(e)) {
1706
+ if (options.throwErrors || !this.hooks.onError.call(e)) {
1493
1707
  throw e;
1494
1708
  }
1495
1709
  }
@@ -1543,25 +1757,18 @@ class ExpressionEvaluator {
1543
1757
  }
1544
1758
  if (node.type === "CallExpression") {
1545
1759
  const expressionName = node.callTarget.name;
1546
- if (expressionName === "conditional") {
1547
- const condition = resolveNode(node.args[0]);
1548
- if (condition) {
1549
- return resolveNode(node.args[1]);
1550
- }
1551
- if (node.args[2]) {
1552
- return resolveNode(node.args[2]);
1553
- }
1554
- return null;
1555
- }
1556
1760
  const operator = this.operators.expressions.get(expressionName);
1557
1761
  if (!operator) {
1558
1762
  throw new Error(`Unknown expression function: ${expressionName}`);
1559
1763
  }
1764
+ if ("resolveParams" in operator && operator.resolveParams === false) {
1765
+ return operator(expressionContext, ...node.args);
1766
+ }
1560
1767
  const args = node.args.map((n) => resolveNode(n));
1561
1768
  return operator(expressionContext, ...args);
1562
1769
  }
1563
1770
  if (node.type === "ModelRef") {
1564
- return model.get(node.ref);
1771
+ return model.get(node.ref, { context: { model: options.model } });
1565
1772
  }
1566
1773
  if (node.type === "MemberExpression") {
1567
1774
  const obj = resolveNode(node.object);
@@ -1613,10 +1820,6 @@ class ExpressionEvaluator {
1613
1820
  }
1614
1821
  }
1615
1822
 
1616
- function withoutContext(fn) {
1617
- return (_context, ...args) => fn(...args);
1618
- }
1619
-
1620
1823
  const severities = ["trace", "debug", "info", "warn", "error"];
1621
1824
 
1622
1825
  class ConsoleLogger {
@@ -1773,6 +1976,9 @@ function parse(schema) {
1773
1976
  if (type.isArray) {
1774
1977
  nestedPath.push("[]");
1775
1978
  }
1979
+ if (type.isRecord) {
1980
+ nestedPath.push("{}");
1981
+ }
1776
1982
  if (type.type && schema[type.type]) {
1777
1983
  parseQueue.push({
1778
1984
  path: nestedPath,
@@ -1821,8 +2027,20 @@ class SchemaController {
1821
2027
  if (cached) {
1822
2028
  return cached;
1823
2029
  }
1824
- const normalized = binding.asArray().map((p) => typeof p === "number" ? "[]" : p).join(".");
1825
- this.bindingSchemaNormalizedCache.set(binding, normalized);
2030
+ let bindingArray = binding.asArray();
2031
+ let normalized = bindingArray.map((p) => typeof p === "number" ? "[]" : p).join(".");
2032
+ if (normalized) {
2033
+ this.bindingSchemaNormalizedCache.set(binding, normalized);
2034
+ bindingArray = normalized.split(".");
2035
+ }
2036
+ bindingArray.forEach((item) => {
2037
+ const recordBinding = bindingArray.map((p) => p === item ? "{}" : p).join(".");
2038
+ if (this.schema.get(recordBinding)) {
2039
+ this.bindingSchemaNormalizedCache.set(binding, recordBinding);
2040
+ bindingArray = recordBinding.split(".");
2041
+ normalized = recordBinding;
2042
+ }
2043
+ });
1826
2044
  return normalized;
1827
2045
  }
1828
2046
  getType(binding) {
@@ -1909,6 +2127,9 @@ function findNextExp(str) {
1909
2127
  };
1910
2128
  }
1911
2129
  function resolveExpressionsInString(val, { evaluate }) {
2130
+ if (!evaluate) {
2131
+ return val;
2132
+ }
1912
2133
  const expMatch = /@\[.*?\]@/;
1913
2134
  let newVal = val;
1914
2135
  let match = newVal.match(expMatch);
@@ -1926,9 +2147,9 @@ function resolveExpressionsInString(val, { evaluate }) {
1926
2147
  return newVal;
1927
2148
  }
1928
2149
  function resolveDataRefsInString(val, options) {
1929
- const { model } = options;
2150
+ const { model, formatted = true } = options;
1930
2151
  let workingString = resolveExpressionsInString(val, options);
1931
- if (typeof workingString !== "string" || workingString.indexOf(DOUBLE_OPEN_CURLY) === -1) {
2152
+ if (!model || typeof workingString !== "string" || workingString.indexOf(DOUBLE_OPEN_CURLY) === -1) {
1932
2153
  return workingString;
1933
2154
  }
1934
2155
  while (workingString.indexOf(DOUBLE_OPEN_CURLY) !== -1) {
@@ -1938,7 +2159,7 @@ function resolveDataRefsInString(val, options) {
1938
2159
  }
1939
2160
  const { start, end } = expLocation;
1940
2161
  const binding = workingString.substring(start + DOUBLE_OPEN_CURLY.length, end - DOUBLE_OPEN_CURLY.length).trim();
1941
- const evaledVal = model.get(binding, { formatted: true });
2162
+ const evaledVal = model.get(binding, { formatted });
1942
2163
  if (start === 0 && end === workingString.length && typeof evaledVal !== "string") {
1943
2164
  return evaledVal;
1944
2165
  }
@@ -1952,12 +2173,14 @@ function traverseObject(val, options) {
1952
2173
  return resolveDataRefsInString(val, options);
1953
2174
  }
1954
2175
  case "object": {
2176
+ if (!val)
2177
+ return val;
1955
2178
  const keys = Object.keys(val);
1956
2179
  let newVal = val;
1957
2180
  if (keys.length > 0) {
1958
- for (const key of keys) {
2181
+ keys.forEach((key) => {
1959
2182
  newVal = setIn(newVal, [key], traverseObject(val[key], options));
1960
- }
2183
+ });
1961
2184
  }
1962
2185
  return newVal;
1963
2186
  }
@@ -1969,6 +2192,36 @@ function resolveDataRefs(val, options) {
1969
2192
  return traverseObject(val, options);
1970
2193
  }
1971
2194
 
2195
+ function removeBindingAndChildrenFromMap(sourceMap, binding) {
2196
+ const targetMap = new Map(sourceMap);
2197
+ const parentBinding = binding.parent();
2198
+ const property = binding.key();
2199
+ targetMap.forEach((_value, trackedBinding) => {
2200
+ if (binding === trackedBinding || binding.contains(trackedBinding)) {
2201
+ targetMap.delete(trackedBinding);
2202
+ }
2203
+ });
2204
+ if (typeof property === "number") {
2205
+ const bindingsToRewrite = Array.from(sourceMap.keys()).filter((b) => {
2206
+ if (parentBinding.contains(b)) {
2207
+ const [childIndex] = b.relative(parentBinding);
2208
+ return typeof childIndex === "number" && childIndex > property;
2209
+ }
2210
+ return false;
2211
+ }).sort();
2212
+ bindingsToRewrite.forEach((trackedBinding) => {
2213
+ const [childIndex, ...childPath] = trackedBinding.relative(parentBinding);
2214
+ if (typeof childIndex === "number") {
2215
+ const newSegments = [childIndex - 1, ...childPath];
2216
+ const newChildBinding = parentBinding.descendent(newSegments);
2217
+ targetMap.set(newChildBinding, targetMap.get(trackedBinding));
2218
+ targetMap.delete(trackedBinding);
2219
+ }
2220
+ });
2221
+ }
2222
+ return targetMap;
2223
+ }
2224
+
1972
2225
  var __defProp$a = Object.defineProperty;
1973
2226
  var __defProps$8 = Object.defineProperties;
1974
2227
  var __getOwnPropDescs$8 = Object.getOwnPropertyDescriptors;
@@ -1993,12 +2246,15 @@ class ValidationMiddleware {
1993
2246
  this.validator = validator;
1994
2247
  this.shadowModelPaths = new Map();
1995
2248
  this.logger = options == null ? void 0 : options.logger;
2249
+ this.shouldIncludeInvalid = options == null ? void 0 : options.shouldIncludeInvalid;
1996
2250
  }
1997
2251
  set(transaction, options, next) {
1998
2252
  const asModel = toModel(this, __spreadProps$8(__spreadValues$a({}, options), { includeInvalid: true }), next);
1999
2253
  const nextTransaction = [];
2254
+ const includedBindings = new Set();
2000
2255
  transaction.forEach(([binding, value]) => {
2001
2256
  this.shadowModelPaths.set(binding, value);
2257
+ includedBindings.add(binding);
2002
2258
  });
2003
2259
  const invalidBindings = [];
2004
2260
  this.shadowModelPaths.forEach((value, binding) => {
@@ -2007,16 +2263,27 @@ class ValidationMiddleware {
2007
2263
  if (validations === void 0) {
2008
2264
  nextTransaction.push([binding, value]);
2009
2265
  } else if (validations instanceof Set) {
2010
- invalidBindings.push(...validations);
2011
- } else {
2266
+ validations.forEach((validation) => {
2267
+ invalidBindings.push(validation.binding);
2268
+ if (!validation.isStrong && validation.binding.asString() === binding.asString()) {
2269
+ nextTransaction.push([validation.binding, value]);
2270
+ }
2271
+ });
2272
+ } else if (includedBindings.has(binding)) {
2273
+ invalidBindings.push(binding);
2012
2274
  (_a = this.logger) == null ? void 0 : _a.debug(`Invalid value for path: ${binding.asString()} - ${validations.severity} - ${validations.message}`);
2013
2275
  }
2014
2276
  });
2277
+ let validResults = [];
2015
2278
  if (next && nextTransaction.length > 0) {
2016
2279
  nextTransaction.forEach(([binding]) => this.shadowModelPaths.delete(binding));
2017
- return next.set(nextTransaction, options);
2280
+ const result = next.set(nextTransaction, options);
2281
+ if (invalidBindings.length === 0) {
2282
+ return result;
2283
+ }
2284
+ validResults = result;
2018
2285
  }
2019
- return invalidBindings.map((binding) => {
2286
+ const invalidResults = invalidBindings.map((binding) => {
2020
2287
  return {
2021
2288
  binding,
2022
2289
  oldValue: asModel.get(binding),
@@ -2024,10 +2291,12 @@ class ValidationMiddleware {
2024
2291
  force: true
2025
2292
  };
2026
2293
  });
2294
+ return [...validResults, ...invalidResults];
2027
2295
  }
2028
2296
  get(binding, options, next) {
2297
+ var _a, _b;
2029
2298
  let val = next == null ? void 0 : next.get(binding, options);
2030
- if ((options == null ? void 0 : options.includeInvalid) === true) {
2299
+ if ((_b = (_a = this.shouldIncludeInvalid) == null ? void 0 : _a.call(this, options)) != null ? _b : (options == null ? void 0 : options.includeInvalid) === true) {
2031
2300
  this.shadowModelPaths.forEach((shadowValue, shadowBinding) => {
2032
2301
  if (shadowBinding === binding) {
2033
2302
  val = shadowValue;
@@ -2040,6 +2309,10 @@ class ValidationMiddleware {
2040
2309
  }
2041
2310
  return val;
2042
2311
  }
2312
+ delete(binding, options, next) {
2313
+ this.shadowModelPaths = removeBindingAndChildrenFromMap(this.shadowModelPaths, binding);
2314
+ return next == null ? void 0 : next.delete(binding, options);
2315
+ }
2043
2316
  }
2044
2317
 
2045
2318
  class ValidatorRegistry {
@@ -2124,6 +2397,9 @@ class Parser {
2124
2397
  }
2125
2398
  return tapped;
2126
2399
  }
2400
+ hasTemplateValues(obj, localKey) {
2401
+ return Object.hasOwnProperty.call(obj, "template") && Array.isArray(obj == null ? void 0 : obj.template) && obj.template.length && obj.template.find((tmpl) => tmpl.output === localKey);
2402
+ }
2127
2403
  parseObject(obj, type = NodeType.Value, options = { templateDepth: 0 }) {
2128
2404
  var _a;
2129
2405
  const nodeType = this.hooks.determineNodeType.call(obj);
@@ -2141,12 +2417,19 @@ class Parser {
2141
2417
  if (!localObj) {
2142
2418
  return currentValue;
2143
2419
  }
2144
- const objEntries = Array.isArray(localObj) ? localObj.map((v, i) => [i, v]) : Object.entries(localObj);
2420
+ const objEntries = Array.isArray(localObj) ? localObj.map((v, i) => [i, v]) : [
2421
+ ...Object.entries(localObj),
2422
+ ...Object.getOwnPropertySymbols(localObj).map((s) => [
2423
+ s,
2424
+ localObj[s]
2425
+ ])
2426
+ ];
2145
2427
  const defaultValue = {
2146
2428
  children: [],
2147
2429
  value: currentValue
2148
2430
  };
2149
2431
  const newValue = objEntries.reduce((accumulation, current) => {
2432
+ var _b;
2150
2433
  const _a2 = accumulation, { children: children2 } = _a2, rest = __objRest$1(_a2, ["children"]);
2151
2434
  const [localKey, localValue] = current;
2152
2435
  if (localKey === "asset" && typeof localValue === "object") {
@@ -2164,14 +2447,19 @@ class Parser {
2164
2447
  }
2165
2448
  } else if (this.hooks.determineNodeType.call(localKey) === NodeType.Template && Array.isArray(localValue)) {
2166
2449
  const templateChildren = localValue.map((template) => {
2167
- var _a3, _b;
2450
+ var _a3, _b2;
2168
2451
  const templateAST = this.hooks.onCreateASTNode.call({
2169
2452
  type: NodeType.Template,
2170
2453
  depth: (_a3 = options.templateDepth) != null ? _a3 : 0,
2171
2454
  data: template.data,
2172
2455
  template: template.value,
2173
- dynamic: (_b = template.dynamic) != null ? _b : false
2456
+ dynamic: (_b2 = template.dynamic) != null ? _b2 : false
2174
2457
  }, template);
2458
+ if ((templateAST == null ? void 0 : templateAST.type) === NodeType.MultiNode) {
2459
+ templateAST.values.forEach((v) => {
2460
+ v.parent = templateAST;
2461
+ });
2462
+ }
2175
2463
  if (templateAST) {
2176
2464
  return {
2177
2465
  path: [...path, template.output],
@@ -2185,6 +2473,18 @@ class Parser {
2185
2473
  });
2186
2474
  } else if (localValue && this.hooks.determineNodeType.call(localValue) === NodeType.Switch) {
2187
2475
  const localSwitch = this.hooks.parseNode.call(localValue, NodeType.Value, options, NodeType.Switch);
2476
+ if (localSwitch && localSwitch.type === NodeType.Value && ((_b = localSwitch.children) == null ? void 0 : _b.length) === 1 && localSwitch.value === void 0) {
2477
+ const firstChild = localSwitch.children[0];
2478
+ return __spreadProps$7(__spreadValues$9({}, rest), {
2479
+ children: [
2480
+ ...children2,
2481
+ {
2482
+ path: [...path, localKey, ...firstChild.path],
2483
+ value: firstChild.value
2484
+ }
2485
+ ]
2486
+ });
2487
+ }
2188
2488
  if (localSwitch) {
2189
2489
  return __spreadProps$7(__spreadValues$9({}, rest), {
2190
2490
  children: [
@@ -2201,7 +2501,7 @@ class Parser {
2201
2501
  if (childValues.length > 0) {
2202
2502
  const multiNode = this.hooks.onCreateASTNode.call({
2203
2503
  type: NodeType.MultiNode,
2204
- override: true,
2504
+ override: !this.hasTemplateValues(localObj, localKey),
2205
2505
  values: childValues
2206
2506
  }, localValue);
2207
2507
  if ((multiNode == null ? void 0 : multiNode.type) === NodeType.MultiNode) {
@@ -2224,7 +2524,7 @@ class Parser {
2224
2524
  } else if (localValue && typeof localValue === "object") {
2225
2525
  const determineNodeType = this.hooks.determineNodeType.call(localValue);
2226
2526
  if (determineNodeType === NodeType.Applicability) {
2227
- const parsedNode = this.hooks.parseNode.call(localValue, type, options, determineNodeType);
2527
+ const parsedNode = this.hooks.parseNode.call(localValue, NodeType.Value, options, determineNodeType);
2228
2528
  if (parsedNode) {
2229
2529
  return __spreadProps$7(__spreadValues$9({}, rest), {
2230
2530
  children: [
@@ -2346,6 +2646,11 @@ const withContext = (model) => {
2346
2646
  return model.set(transaction, __spreadValues$7({
2347
2647
  context: { model }
2348
2648
  }, options));
2649
+ },
2650
+ delete: (binding, options) => {
2651
+ return model.delete(binding, __spreadValues$7({
2652
+ context: { model }
2653
+ }, options));
2349
2654
  }
2350
2655
  };
2351
2656
  };
@@ -2375,12 +2680,16 @@ class Resolver {
2375
2680
  this.hooks.beforeUpdate.call(changes);
2376
2681
  const resolveCache = new Map();
2377
2682
  this.idCache.clear();
2683
+ const prevASTMap = new Map(this.ASTMap);
2378
2684
  this.ASTMap.clear();
2379
- const updated = this.computeTree(this.root, void 0, changes, resolveCache, toNodeResolveOptions(this.options));
2685
+ const updated = this.computeTree(this.root, void 0, changes, resolveCache, toNodeResolveOptions(this.options), void 0, prevASTMap);
2380
2686
  this.resolveCache = resolveCache;
2381
2687
  this.hooks.afterUpdate.call(updated.value);
2382
2688
  return updated.value;
2383
2689
  }
2690
+ getResolveCache() {
2691
+ return new Map(this.resolveCache);
2692
+ }
2384
2693
  getNodeID(node) {
2385
2694
  var _a;
2386
2695
  if (!node) {
@@ -2412,7 +2721,19 @@ class Resolver {
2412
2721
  }
2413
2722
  return this.resolveCache.get(node);
2414
2723
  }
2415
- computeTree(node, parent, dataChanges, cacheUpdate, options) {
2724
+ cloneNode(node) {
2725
+ const clonedNode = clone(node);
2726
+ Object.keys(clonedNode).forEach((key) => {
2727
+ if (key === "parent")
2728
+ return;
2729
+ const value = clonedNode[key];
2730
+ if (typeof value === "object" && value !== null) {
2731
+ clonedNode[key] = Array.isArray(value) ? [...value] : __spreadValues$7({}, value);
2732
+ }
2733
+ });
2734
+ return clonedNode;
2735
+ }
2736
+ computeTree(node, parent, dataChanges, cacheUpdate, options, parentNode, prevASTMap) {
2416
2737
  var _a, _b;
2417
2738
  const dependencyModel = new DependencyModel(options.data.model);
2418
2739
  dependencyModel.trackSubset("core");
@@ -2433,34 +2754,40 @@ class Resolver {
2433
2754
  updated: false
2434
2755
  });
2435
2756
  cacheUpdate.set(node, update2);
2436
- const repopulateASTMapFromCache = (resolvedAST3, AST) => {
2757
+ const repopulateASTMapFromCache = (resolvedNode, AST, ASTParent) => {
2437
2758
  var _a2;
2438
- this.ASTMap.set(resolvedAST3, AST);
2439
- if ("children" in resolvedAST3) {
2440
- (_a2 = resolvedAST3.children) == null ? void 0 : _a2.forEach(({ value: childAST }) => {
2441
- const { node: childResolvedAST } = this.getPreviousResult(childAST) || {};
2442
- if (!childResolvedAST)
2443
- return;
2444
- repopulateASTMapFromCache(childResolvedAST, childAST);
2445
- if (childResolvedAST.type === NodeType.MultiNode) {
2446
- childResolvedAST.values.forEach((mChildAST) => {
2447
- const { node: mChildResolvedAST } = this.getPreviousResult(mChildAST) || {};
2448
- if (!mChildResolvedAST)
2449
- return;
2450
- repopulateASTMapFromCache(mChildResolvedAST, mChildAST);
2451
- });
2452
- }
2453
- });
2759
+ const { node: resolvedAST2 } = resolvedNode;
2760
+ this.ASTMap.set(resolvedAST2, AST);
2761
+ const resolvedUpdate = __spreadProps$5(__spreadValues$7({}, resolvedNode), {
2762
+ updated: false
2763
+ });
2764
+ cacheUpdate.set(AST, resolvedUpdate);
2765
+ const handleChildNode = (childNode) => {
2766
+ var _a3;
2767
+ const originalChildNode = (_a3 = prevASTMap.get(childNode)) != null ? _a3 : childNode;
2768
+ const previousChildResult = this.getPreviousResult(originalChildNode);
2769
+ if (!previousChildResult)
2770
+ return;
2771
+ repopulateASTMapFromCache(previousChildResult, originalChildNode, AST);
2772
+ };
2773
+ if ("children" in resolvedAST2) {
2774
+ (_a2 = resolvedAST2.children) == null ? void 0 : _a2.forEach(({ value: childAST }) => handleChildNode(childAST));
2775
+ } else if (resolvedAST2.type === NodeType.MultiNode) {
2776
+ resolvedAST2.values.forEach(handleChildNode);
2454
2777
  }
2778
+ this.hooks.afterNodeUpdate.call(AST, ASTParent, resolvedUpdate);
2455
2779
  };
2456
- const resolvedAST2 = previousResult.node;
2457
- repopulateASTMapFromCache(resolvedAST2, node);
2458
- this.hooks.afterNodeUpdate.call(node, parent, update2);
2780
+ previousResult.node.parent = parentNode;
2781
+ repopulateASTMapFromCache(previousResult, node, parent);
2459
2782
  return update2;
2460
2783
  }
2461
- const resolvedAST = (_a = this.hooks.beforeResolve.call(node, resolveOptions)) != null ? _a : {
2784
+ const clonedNode = __spreadProps$5(__spreadValues$7({}, this.cloneNode(node)), {
2785
+ parent: parentNode
2786
+ });
2787
+ const resolvedAST = (_a = this.hooks.beforeResolve.call(clonedNode, resolveOptions)) != null ? _a : {
2462
2788
  type: NodeType.Empty
2463
2789
  };
2790
+ resolvedAST.parent = parentNode;
2464
2791
  resolveOptions.node = resolvedAST;
2465
2792
  this.ASTMap.set(resolvedAST, node);
2466
2793
  let resolved = this.hooks.resolve.call(void 0, resolvedAST, resolveOptions);
@@ -2471,22 +2798,15 @@ class Resolver {
2471
2798
  const childDependencies = new Set();
2472
2799
  dependencyModel.trackSubset("children");
2473
2800
  if ("children" in resolvedAST) {
2474
- (_b = resolvedAST.children) == null ? void 0 : _b.forEach((child) => {
2475
- const computedChildTree = this.computeTree(child.value, node, dataChanges, cacheUpdate, resolveOptions);
2476
- let { updated: childUpdated, value: childValue } = computedChildTree;
2477
- const { node: childNode, dependencies: childTreeDeps } = computedChildTree;
2801
+ const newChildren = (_b = resolvedAST.children) == null ? void 0 : _b.map((child) => {
2802
+ const computedChildTree = this.computeTree(child.value, node, dataChanges, cacheUpdate, resolveOptions, resolvedAST, prevASTMap);
2803
+ const {
2804
+ dependencies: childTreeDeps,
2805
+ node: childNode,
2806
+ updated: childUpdated,
2807
+ value: childValue
2808
+ } = computedChildTree;
2478
2809
  childTreeDeps.forEach((binding) => childDependencies.add(binding));
2479
- if (childNode.type === NodeType.MultiNode) {
2480
- childValue = [];
2481
- childNode.values.forEach((mValue) => {
2482
- const mTree = this.computeTree(mValue, node, dataChanges, cacheUpdate, resolveOptions);
2483
- if (mTree.value !== void 0 && mTree.value !== null) {
2484
- childValue.push(mTree.value);
2485
- }
2486
- mTree.dependencies.forEach((bindingDep) => childDependencies.add(bindingDep));
2487
- childUpdated = childUpdated || mTree.updated;
2488
- });
2489
- }
2490
2810
  if (childValue) {
2491
2811
  if (childNode.type === NodeType.MultiNode && !childNode.override) {
2492
2812
  const arr = addLast(get(resolved, child.path, []), childValue);
@@ -2496,7 +2816,22 @@ class Resolver {
2496
2816
  }
2497
2817
  }
2498
2818
  updated = updated || childUpdated;
2819
+ return __spreadProps$5(__spreadValues$7({}, child), { value: childNode });
2499
2820
  });
2821
+ resolvedAST.children = newChildren;
2822
+ } else if (resolvedAST.type === NodeType.MultiNode) {
2823
+ const childValue = [];
2824
+ const newValues = resolvedAST.values.map((mValue) => {
2825
+ const mTree = this.computeTree(mValue, node, dataChanges, cacheUpdate, resolveOptions, resolvedAST, prevASTMap);
2826
+ if (mTree.value !== void 0 && mTree.value !== null) {
2827
+ childValue.push(mTree.value);
2828
+ }
2829
+ mTree.dependencies.forEach((bindingDep) => childDependencies.add(bindingDep));
2830
+ updated = updated || mTree.updated;
2831
+ return mTree.node;
2832
+ });
2833
+ resolvedAST.values = newValues;
2834
+ resolved = childValue;
2500
2835
  }
2501
2836
  childDependencies.forEach((bindingDep) => dependencyModel.addChildReadDep(bindingDep));
2502
2837
  dependencyModel.trackSubset("core");
@@ -2565,13 +2900,10 @@ class TemplatePlugin {
2565
2900
  }
2566
2901
  });
2567
2902
  const result = {
2568
- parent: node.parent,
2569
2903
  type: NodeType.MultiNode,
2904
+ override: false,
2570
2905
  values
2571
2906
  };
2572
- result.values.forEach((innerNode) => {
2573
- innerNode.parent = result;
2574
- });
2575
2907
  return result;
2576
2908
  }
2577
2909
  applyParser(parser) {
@@ -2665,30 +2997,44 @@ function resolveAllRefs(node, resolveOptions, propertiesToSkip) {
2665
2997
  });
2666
2998
  return newNode;
2667
2999
  }
2668
- const findBasePath = (node) => {
3000
+ const findBasePath = (node, resolver) => {
2669
3001
  var _a, _b, _c;
2670
3002
  const parentNode = node.parent;
2671
3003
  if (!parentNode) {
2672
3004
  return [];
2673
3005
  }
2674
3006
  if ("children" in parentNode) {
2675
- return (_c = (_b = (_a = parentNode.children) == null ? void 0 : _a.find((child) => child.value === node)) == null ? void 0 : _b.path) != null ? _c : [];
3007
+ const original = resolver.getSourceNode(node);
3008
+ return (_c = (_b = (_a = parentNode.children) == null ? void 0 : _a.find((child) => child.value === original)) == null ? void 0 : _b.path) != null ? _c : [];
2676
3009
  }
2677
3010
  if (parentNode.type !== NodeType.MultiNode) {
2678
3011
  return [];
2679
3012
  }
2680
- return findBasePath(parentNode);
3013
+ return findBasePath(parentNode, resolver);
2681
3014
  };
2682
3015
  class StringResolverPlugin {
3016
+ constructor() {
3017
+ this.propertiesToSkipCache = new Map();
3018
+ }
2683
3019
  applyResolver(resolver) {
2684
3020
  resolver.hooks.resolve.tap("string-resolver", (value, node, options) => {
2685
- var _a, _b, _c, _d;
3021
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2686
3022
  if (node.type === NodeType.Empty || node.type === NodeType.Unknown) {
2687
3023
  return null;
2688
3024
  }
2689
3025
  if (node.type === NodeType.Value || node.type === NodeType.Asset || node.type === NodeType.View) {
2690
- 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 : []);
2691
- const nodePath = findBasePath(node);
3026
+ let propsToSkip;
3027
+ if (node.type === NodeType.Asset || node.type === NodeType.View) {
3028
+ propsToSkip = new Set((_c = (_b = (_a = node.plugins) == null ? void 0 : _a.stringResolver) == null ? void 0 : _b.propertiesToSkip) != null ? _c : ["exp"]);
3029
+ if ((_d = node.value) == null ? void 0 : _d.id) {
3030
+ this.propertiesToSkipCache.set(node.value.id, propsToSkip);
3031
+ }
3032
+ } else if (((_e = node.parent) == null ? void 0 : _e.type) === NodeType.MultiNode && (((_g = (_f = node.parent) == null ? void 0 : _f.parent) == null ? void 0 : _g.type) === NodeType.Asset || ((_i = (_h = node.parent) == null ? void 0 : _h.parent) == null ? void 0 : _i.type) === NodeType.View) && ((_j = node.parent.parent.value) == null ? void 0 : _j.id) && this.propertiesToSkipCache.has(node.parent.parent.value.id)) {
3033
+ propsToSkip = this.propertiesToSkipCache.get(node.parent.parent.value.id);
3034
+ } else {
3035
+ propsToSkip = new Set(["exp"]);
3036
+ }
3037
+ const nodePath = findBasePath(node, resolver);
2692
3038
  if (nodePath.length > 0 && nodePath.some((segment) => propsToSkip.has(segment.toString()))) {
2693
3039
  return node.value;
2694
3040
  }
@@ -2708,7 +3054,7 @@ class ApplicabilityPlugin {
2708
3054
  let newNode = node;
2709
3055
  if ((node == null ? void 0 : node.type) === NodeType.Applicability) {
2710
3056
  const isApplicable = options.evaluate(node.expression);
2711
- if (!isApplicable) {
3057
+ if (isApplicable === false) {
2712
3058
  return null;
2713
3059
  }
2714
3060
  newNode = node.value;
@@ -3014,7 +3360,8 @@ class FlowInstance {
3014
3360
  skipTransition: new SyncBailHook(),
3015
3361
  beforeTransition: new SyncWaterfallHook(),
3016
3362
  resolveTransitionNode: new SyncWaterfallHook(),
3017
- transition: new SyncHook()
3363
+ transition: new SyncHook(),
3364
+ afterTransition: new SyncHook()
3018
3365
  };
3019
3366
  this.id = id;
3020
3367
  this.flow = flow;
@@ -3061,7 +3408,7 @@ class FlowInstance {
3061
3408
  } else {
3062
3409
  const skipTransition = this.hooks.skipTransition.call(this.currentState);
3063
3410
  if (skipTransition) {
3064
- (_d = this.log) == null ? void 0 : _d.debug(`Skipping transition from ${this.currentState} b/c hook told us to`);
3411
+ (_d = this.log) == null ? void 0 : _d.debug(`Skipping transition from ${this.currentState.name} b/c hook told us to`);
3065
3412
  return;
3066
3413
  }
3067
3414
  }
@@ -3100,6 +3447,7 @@ class FlowInstance {
3100
3447
  this.hooks.onEnd.call(this.flow.onEnd);
3101
3448
  }
3102
3449
  this.hooks.transition.call(prevState, __spreadValues$5({}, newCurrentState));
3450
+ this.hooks.afterTransition.call(this);
3103
3451
  }
3104
3452
  }
3105
3453
 
@@ -3134,6 +3482,7 @@ class FlowController {
3134
3482
  this.start = this.start.bind(this);
3135
3483
  this.run = this.run.bind(this);
3136
3484
  this.transition = this.transition.bind(this);
3485
+ this.addNewFlow = this.addNewFlow.bind(this);
3137
3486
  }
3138
3487
  transition(stateTransition, options) {
3139
3488
  if (this.current === void 0) {
@@ -3142,20 +3491,9 @@ class FlowController {
3142
3491
  this.current.transition(stateTransition, options);
3143
3492
  }
3144
3493
  addNewFlow(flow) {
3145
- return __async$1(this, null, function* () {
3146
- this.navStack.push(flow);
3147
- this.current = flow;
3148
- flow.hooks.transition.tap("flow-controller", (_oldState, newState) => __async$1(this, null, function* () {
3149
- var _a, _b;
3150
- if (newState.value.state_type === "FLOW") {
3151
- (_a = this.log) == null ? void 0 : _a.debug(`Got FLOW state. Loading flow ${newState.value.ref}`);
3152
- const endState = yield this.run(newState.value.ref);
3153
- (_b = this.log) == null ? void 0 : _b.debug(`Flow ended. Using outcome: ${endState.outcome}`);
3154
- flow.transition(endState.outcome);
3155
- }
3156
- }));
3157
- this.hooks.flow.call(flow);
3158
- });
3494
+ this.navStack.push(flow);
3495
+ this.current = flow;
3496
+ this.hooks.flow.call(flow);
3159
3497
  }
3160
3498
  run(startState) {
3161
3499
  return __async$1(this, null, function* () {
@@ -3170,6 +3508,18 @@ class FlowController {
3170
3508
  (_a = this.log) == null ? void 0 : _a.debug(`Starting flow: ${startState}`);
3171
3509
  const flow = new FlowInstance(startState, startFlow, { logger: this.log });
3172
3510
  this.addNewFlow(flow);
3511
+ flow.hooks.afterTransition.tap("flow-controller", (flowInstance) => {
3512
+ var _a2, _b, _c;
3513
+ if (((_a2 = flowInstance.currentState) == null ? void 0 : _a2.value.state_type) === "FLOW") {
3514
+ const subflowId = (_b = flowInstance.currentState) == null ? void 0 : _b.value.ref;
3515
+ (_c = this.log) == null ? void 0 : _c.debug(`Loading subflow ${subflowId}`);
3516
+ this.run(subflowId).then((subFlowEndState) => {
3517
+ var _a3;
3518
+ (_a3 = this.log) == null ? void 0 : _a3.debug(`Subflow ended. Using outcome: ${subFlowEndState.outcome}`);
3519
+ flowInstance.transition(subFlowEndState == null ? void 0 : subFlowEndState.outcome);
3520
+ });
3521
+ }
3522
+ });
3173
3523
  const end = yield flow.start();
3174
3524
  this.navStack.pop();
3175
3525
  if (this.navStack.length > 0) {
@@ -3222,11 +3572,18 @@ class ValidationBindingTrackerViewPlugin {
3222
3572
  getBindings() {
3223
3573
  return this.trackedBindings;
3224
3574
  }
3575
+ trackBinding(binding) {
3576
+ var _a, _b;
3577
+ if (this.trackedBindings.has(binding)) {
3578
+ return;
3579
+ }
3580
+ this.trackedBindings.add(binding);
3581
+ (_b = (_a = this.options.callbacks) == null ? void 0 : _a.onAdd) == null ? void 0 : _b.call(_a, binding);
3582
+ }
3225
3583
  applyResolver(resolver) {
3226
3584
  this.trackedBindings.clear();
3227
3585
  const tracked = new Map();
3228
3586
  const sections = new Map();
3229
- const seenBindings = new Set();
3230
3587
  let lastViewUpdateChangeSet;
3231
3588
  const nodeTree = new Map();
3232
3589
  let lastComputedBindingTree = new Map();
@@ -3273,31 +3630,34 @@ class ValidationBindingTrackerViewPlugin {
3273
3630
  parent = parent.parent;
3274
3631
  }
3275
3632
  }
3276
- if (!seenBindings.has(parsed)) {
3277
- seenBindings.add(parsed);
3278
- (_d = (_c = this.options.callbacks) == null ? void 0 : _c.onAdd) == null ? void 0 : _d.call(_c, parsed);
3279
- }
3633
+ this.trackedBindings.add(parsed);
3634
+ (_d = (_c = this.options.callbacks) == null ? void 0 : _c.onAdd) == null ? void 0 : _d.call(_c, parsed);
3280
3635
  };
3281
3636
  return __spreadProps$3(__spreadValues$4({}, options), {
3282
3637
  validation: __spreadProps$3(__spreadValues$4({}, options.validation), {
3283
3638
  get: (binding, getOptions) => {
3284
- var _a;
3639
+ var _a, _b;
3285
3640
  if (getOptions == null ? void 0 : getOptions.track) {
3286
3641
  track(binding);
3287
3642
  }
3288
- const eow = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding);
3289
- if ((eow == null ? void 0 : eow.displayTarget) === void 0 || (eow == null ? void 0 : eow.displayTarget) === "field") {
3290
- return eow;
3643
+ const eows = (_b = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding)) == null ? void 0 : _b.getAll(getOptions);
3644
+ const firstFieldEOW = eows == null ? void 0 : eows.find((eow) => eow.displayTarget === "field" || eow.displayTarget === void 0);
3645
+ return firstFieldEOW;
3646
+ },
3647
+ getValidationsForBinding(binding, getOptions) {
3648
+ var _a, _b, _c;
3649
+ if (getOptions == null ? void 0 : getOptions.track) {
3650
+ track(binding);
3291
3651
  }
3292
- return void 0;
3652
+ return (_c = (_b = (_a = options.validation) == null ? void 0 : _a._getValidationForBinding(binding)) == null ? void 0 : _b.getAll(getOptions)) != null ? _c : [];
3293
3653
  },
3294
3654
  getChildren: (type) => {
3295
3655
  var _a;
3296
3656
  const validations = new Array();
3297
3657
  (_a = lastComputedBindingTree.get(node)) == null ? void 0 : _a.forEach((binding) => {
3298
- var _a2;
3299
- const eow = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding);
3300
- if (eow && type === eow.displayTarget) {
3658
+ var _a2, _b;
3659
+ const eow = (_b = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding)) == null ? void 0 : _b.get();
3660
+ if (eow && (type === void 0 || type === eow.displayTarget)) {
3301
3661
  validations.push(eow);
3302
3662
  }
3303
3663
  });
@@ -3307,8 +3667,8 @@ class ValidationBindingTrackerViewPlugin {
3307
3667
  var _a;
3308
3668
  const validations = new Array();
3309
3669
  (_a = lastSectionBindingTree.get(node)) == null ? void 0 : _a.forEach((binding) => {
3310
- var _a2;
3311
- const eow = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding);
3670
+ var _a2, _b;
3671
+ const eow = (_b = (_a2 = options.validation) == null ? void 0 : _a2._getValidationForBinding(binding)) == null ? void 0 : _b.get();
3312
3672
  if (eow && eow.displayTarget === "section") {
3313
3673
  validations.push(eow);
3314
3674
  }
@@ -3327,7 +3687,7 @@ class ValidationBindingTrackerViewPlugin {
3327
3687
  });
3328
3688
  });
3329
3689
  resolver.hooks.afterNodeUpdate.tap(CONTEXT, (node, parent, update) => {
3330
- var _a, _b, _c;
3690
+ var _a, _b;
3331
3691
  if (parent) {
3332
3692
  addToTree(node, parent);
3333
3693
  }
@@ -3342,7 +3702,7 @@ class ValidationBindingTrackerViewPlugin {
3342
3702
  currentBindingTree.set(node, (_b = lastComputedBindingTree.get(node)) != null ? _b : new Set());
3343
3703
  }
3344
3704
  if (node === resolver.root) {
3345
- this.trackedBindings = (_c = currentBindingTree.get(node)) != null ? _c : new Set();
3705
+ this.trackedBindings = new Set(currentBindingTree.get(node));
3346
3706
  lastComputedBindingTree = currentBindingTree;
3347
3707
  lastSectionBindingTree.clear();
3348
3708
  sections.forEach((nodeSet, sectionNode) => {
@@ -3384,11 +3744,23 @@ var __spreadValues$3 = (a, b) => {
3384
3744
  return a;
3385
3745
  };
3386
3746
  var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
3747
+ const SCHEMA_VALIDATION_PROVIDER_NAME = "schema";
3748
+ const VIEW_VALIDATION_PROVIDER_NAME = "view";
3749
+ const VALIDATION_PROVIDER_NAME_SYMBOL = Symbol.for("validation-provider-name");
3750
+ function isSubset(subset, containingSet) {
3751
+ if (subset.size > containingSet.size)
3752
+ return false;
3753
+ for (const entry of subset)
3754
+ if (!containingSet.has(entry))
3755
+ return false;
3756
+ return true;
3757
+ }
3387
3758
  function createStatefulValidationObject(obj) {
3388
3759
  return {
3389
3760
  value: obj,
3390
3761
  type: obj.severity,
3391
- state: "none"
3762
+ state: "none",
3763
+ isBlockingNavigation: false
3392
3764
  };
3393
3765
  }
3394
3766
  class ValidatedBinding {
@@ -3403,44 +3775,68 @@ class ValidatedBinding {
3403
3775
  possibleValidations.forEach((vObj) => {
3404
3776
  const { trigger } = vObj;
3405
3777
  if (this.validationsByState[trigger]) {
3406
- this.validationsByState[trigger].push(createStatefulValidationObject(vObj));
3778
+ const statefulValidationObject = createStatefulValidationObject(vObj);
3779
+ this.validationsByState[trigger].push(statefulValidationObject);
3407
3780
  } else {
3408
3781
  log == null ? void 0 : log.warn(`Unknown validation trigger: ${trigger}`);
3409
3782
  }
3410
3783
  });
3411
3784
  this.weakBindings = weakBindings != null ? weakBindings : new Set();
3412
3785
  }
3786
+ get allValidations() {
3787
+ return Object.values(this.validationsByState).flat();
3788
+ }
3789
+ checkIfBlocking(statefulObj) {
3790
+ if (statefulObj.state === "active") {
3791
+ const { isBlockingNavigation } = statefulObj;
3792
+ return isBlockingNavigation;
3793
+ }
3794
+ return false;
3795
+ }
3796
+ getAll() {
3797
+ return this.applicableValidations.reduce((all, statefulObj) => {
3798
+ if (statefulObj.state === "active" && statefulObj.response) {
3799
+ return [
3800
+ ...all,
3801
+ __spreadProps$2(__spreadValues$3({}, statefulObj.response), {
3802
+ blocking: this.checkIfBlocking(statefulObj)
3803
+ })
3804
+ ];
3805
+ }
3806
+ return all;
3807
+ }, []);
3808
+ }
3413
3809
  get() {
3414
- const firstError = this.applicableValidations.find((statefulObj) => {
3415
- const blocking = this.currentPhase === "navigation" ? statefulObj.value.blocking : true;
3416
- return statefulObj.state === "active" && blocking !== false;
3810
+ const firstInvalid = this.applicableValidations.find((statefulObj) => {
3811
+ return statefulObj.state === "active" && statefulObj.response;
3417
3812
  });
3418
- if ((firstError == null ? void 0 : firstError.state) === "active") {
3419
- return firstError.response;
3813
+ if ((firstInvalid == null ? void 0 : firstInvalid.state) === "active") {
3814
+ return __spreadProps$2(__spreadValues$3({}, firstInvalid.response), {
3815
+ blocking: this.checkIfBlocking(firstInvalid)
3816
+ });
3420
3817
  }
3421
3818
  }
3422
- runApplicableValidations(runner, canDismiss) {
3423
- this.applicableValidations = this.applicableValidations.map((obj) => {
3819
+ runApplicableValidations(runner, canDismiss, phase) {
3820
+ this.applicableValidations = this.applicableValidations.map((originalValue) => {
3424
3821
  var _a, _b, _c;
3425
- if (obj.state === "dismissed") {
3426
- return obj;
3822
+ if (originalValue.state === "dismissed") {
3823
+ return originalValue;
3427
3824
  }
3428
- const blocking = (_a = obj.value.blocking) != null ? _a : obj.value.severity === "warning" && "once" || obj.value.severity === "error" && true;
3429
- const dismissable = canDismiss && blocking === "once";
3430
- if (this.currentPhase === "navigation" && obj.state === "active" && dismissable) {
3825
+ const blocking = (_a = originalValue.value.blocking) != null ? _a : originalValue.value.severity === "warning" && "once" || true;
3826
+ const obj = setIn(originalValue, ["value", "blocking"], blocking);
3827
+ const isBlockingNavigation = blocking === true || blocking === "once" && !canDismiss;
3828
+ if (phase === "navigation" && obj.state === "active" && obj.value.blocking !== true) {
3431
3829
  if (obj.value.severity === "warning") {
3432
3830
  const warn = obj;
3433
- if (warn.dismissable && warn.response.dismiss) {
3831
+ if (warn.dismissable && warn.response.dismiss && (warn.response.blocking !== "once" || !warn.response.blocking)) {
3434
3832
  warn.response.dismiss();
3435
3833
  } else {
3834
+ if ((warn == null ? void 0 : warn.response.blocking) === "once") {
3835
+ warn.response.blocking = false;
3836
+ }
3436
3837
  warn.dismissable = true;
3437
3838
  }
3438
- return obj;
3439
- }
3440
- if (obj.value.severity === "error") {
3441
- const err = obj;
3442
- err.state = "none";
3443
- return obj;
3839
+ return warn;
3444
3840
  }
3445
3841
  }
3446
3842
  const response = runner(obj.value);
@@ -3448,7 +3844,8 @@ class ValidatedBinding {
3448
3844
  type: obj.type,
3449
3845
  value: obj.value,
3450
3846
  state: response ? "active" : "none",
3451
- dismissable: obj.value.severity === "warning" && this.currentPhase === "navigation",
3847
+ isBlockingNavigation,
3848
+ dismissable: obj.value.severity === "warning" && phase === "navigation",
3452
3849
  response: response ? __spreadProps$2(__spreadValues$3({}, obj.value), {
3453
3850
  message: (_b = response.message) != null ? _b : "Something is broken",
3454
3851
  severity: obj.value.severity,
@@ -3466,11 +3863,12 @@ class ValidatedBinding {
3466
3863
  });
3467
3864
  }
3468
3865
  update(phase, canDismiss, runner) {
3866
+ const newApplicableValidations = [];
3469
3867
  if (phase === "load" && this.currentPhase !== void 0) {
3470
3868
  return;
3471
3869
  }
3472
3870
  if (this.currentPhase === "navigation" || phase === this.currentPhase) {
3473
- this.runApplicableValidations(runner, canDismiss);
3871
+ this.runApplicableValidations(runner, canDismiss, phase);
3474
3872
  return;
3475
3873
  }
3476
3874
  if (phase === "load") {
@@ -3483,14 +3881,19 @@ class ValidatedBinding {
3483
3881
  ...this.validationsByState.change
3484
3882
  ];
3485
3883
  } else if (phase === "navigation" && (this.currentPhase === "load" || this.currentPhase === "change")) {
3884
+ this.applicableValidations.forEach((element) => {
3885
+ if (!(element.type === "error" && element.state === "active" && element.isBlockingNavigation === false)) {
3886
+ newApplicableValidations.push(element);
3887
+ }
3888
+ });
3486
3889
  this.applicableValidations = [
3487
- ...this.applicableValidations,
3488
- ...this.currentPhase === "load" ? this.validationsByState.change : [],
3489
- ...this.validationsByState.navigation
3890
+ ...newApplicableValidations,
3891
+ ...this.validationsByState.navigation,
3892
+ ...this.currentPhase === "load" ? this.validationsByState.change : []
3490
3893
  ];
3491
3894
  this.currentPhase = "navigation";
3492
3895
  }
3493
- this.runApplicableValidations(runner, canDismiss);
3896
+ this.runApplicableValidations(runner, canDismiss, phase);
3494
3897
  }
3495
3898
  }
3496
3899
  class ValidationController {
@@ -3498,34 +3901,63 @@ class ValidationController {
3498
3901
  this.hooks = {
3499
3902
  createValidatorRegistry: new SyncHook(),
3500
3903
  onAddValidation: new SyncWaterfallHook(),
3501
- onRemoveValidation: new SyncWaterfallHook()
3904
+ onRemoveValidation: new SyncWaterfallHook(),
3905
+ resolveValidationProviders: new SyncWaterfallHook(),
3906
+ onTrackBinding: new SyncHook()
3502
3907
  };
3503
3908
  this.validations = new Map();
3504
3909
  this.weakBindingTracker = new Set();
3505
- this.lastActiveBindings = new Set();
3506
3910
  this.schema = schema;
3507
3911
  this.options = options;
3508
- this.providers = [schema];
3912
+ this.reset();
3509
3913
  }
3510
3914
  setOptions(options) {
3511
3915
  this.options = options;
3512
3916
  }
3513
3917
  getDataMiddleware() {
3514
3918
  return [
3919
+ {
3920
+ set: (transaction, options, next) => {
3921
+ var _a;
3922
+ return (_a = next == null ? void 0 : next.set(transaction, options)) != null ? _a : [];
3923
+ },
3924
+ get: (binding, options, next) => {
3925
+ return next == null ? void 0 : next.get(binding, options);
3926
+ },
3927
+ delete: (binding, options, next) => {
3928
+ this.validations = removeBindingAndChildrenFromMap(this.validations, binding);
3929
+ return next == null ? void 0 : next.delete(binding, options);
3930
+ }
3931
+ },
3515
3932
  new ValidationMiddleware((binding) => {
3933
+ var _a;
3516
3934
  if (!this.options) {
3517
3935
  return;
3518
3936
  }
3519
3937
  this.updateValidationsForBinding(binding, "change", this.options);
3520
3938
  const strongValidation = this.getValidationForBinding(binding);
3521
- if (strongValidation == null ? void 0 : strongValidation.get())
3939
+ if (((_a = strongValidation == null ? void 0 : strongValidation.get()) == null ? void 0 : _a.severity) === "error") {
3522
3940
  return strongValidation.get();
3941
+ }
3523
3942
  const newInvalidBindings = new Set();
3524
- for (const [, weakValidation] of Array.from(this.validations)) {
3525
- if (caresAboutDataChanges(new Set([binding]), weakValidation.weakBindings) && (weakValidation == null ? void 0 : weakValidation.get())) {
3526
- weakValidation == null ? void 0 : weakValidation.weakBindings.forEach(newInvalidBindings.add, newInvalidBindings);
3943
+ this.validations.forEach((weakValidation, strongBinding) => {
3944
+ var _a2;
3945
+ if (caresAboutDataChanges(new Set([binding]), weakValidation.weakBindings) && ((_a2 = weakValidation == null ? void 0 : weakValidation.get()) == null ? void 0 : _a2.severity) === "error") {
3946
+ weakValidation == null ? void 0 : weakValidation.weakBindings.forEach((weakBinding) => {
3947
+ if (weakBinding === strongBinding) {
3948
+ newInvalidBindings.add({
3949
+ binding: weakBinding,
3950
+ isStrong: true
3951
+ });
3952
+ } else {
3953
+ newInvalidBindings.add({
3954
+ binding: weakBinding,
3955
+ isStrong: false
3956
+ });
3957
+ }
3958
+ });
3527
3959
  }
3528
- }
3960
+ });
3529
3961
  if (newInvalidBindings.size > 0) {
3530
3962
  return newInvalidBindings;
3531
3963
  }
@@ -3535,6 +3967,35 @@ class ValidationController {
3535
3967
  }) })
3536
3968
  ];
3537
3969
  }
3970
+ getValidationProviders() {
3971
+ if (this.providers) {
3972
+ return this.providers;
3973
+ }
3974
+ this.providers = this.hooks.resolveValidationProviders.call([
3975
+ {
3976
+ source: SCHEMA_VALIDATION_PROVIDER_NAME,
3977
+ provider: this.schema
3978
+ },
3979
+ {
3980
+ source: VIEW_VALIDATION_PROVIDER_NAME,
3981
+ provider: {
3982
+ getValidationsForBinding: (binding) => {
3983
+ var _a, _b;
3984
+ return (_b = (_a = this.viewValidationProvider) == null ? void 0 : _a.getValidationsForBinding) == null ? void 0 : _b.call(_a, binding);
3985
+ },
3986
+ getValidationsForView: () => {
3987
+ var _a, _b;
3988
+ return (_b = (_a = this.viewValidationProvider) == null ? void 0 : _a.getValidationsForView) == null ? void 0 : _b.call(_a);
3989
+ }
3990
+ }
3991
+ }
3992
+ ]);
3993
+ return this.providers;
3994
+ }
3995
+ reset() {
3996
+ this.validations.clear();
3997
+ this.tracker = void 0;
3998
+ }
3538
3999
  onView(view) {
3539
4000
  this.validations.clear();
3540
4001
  if (!this.options) {
@@ -3543,7 +4004,7 @@ class ValidationController {
3543
4004
  const bindingTrackerPlugin = new ValidationBindingTrackerViewPlugin(__spreadProps$2(__spreadValues$3({}, this.options), {
3544
4005
  callbacks: {
3545
4006
  onAdd: (binding) => {
3546
- if (!this.options) {
4007
+ if (!this.options || this.getValidationForBinding(binding) !== void 0) {
3547
4008
  return;
3548
4009
  }
3549
4010
  const originalValue = this.options.model.get(binding);
@@ -3551,26 +4012,35 @@ class ValidationController {
3551
4012
  ignoreDefaultValue: true
3552
4013
  });
3553
4014
  if (originalValue !== withoutDefault) {
3554
- this.options.model.set([[binding, originalValue]]);
4015
+ this.options.model.set([[binding, originalValue]], {
4016
+ silent: true
4017
+ });
3555
4018
  }
3556
4019
  this.updateValidationsForBinding(binding, "load", this.options, () => {
3557
4020
  view.update(new Set([binding]));
3558
4021
  });
4022
+ this.hooks.onTrackBinding.call(binding);
3559
4023
  }
3560
4024
  }
3561
4025
  }));
3562
4026
  this.tracker = bindingTrackerPlugin;
3563
- this.providers = [this.schema, view];
4027
+ this.viewValidationProvider = view;
3564
4028
  bindingTrackerPlugin.apply(view);
3565
4029
  }
3566
- updateValidationsForBinding(binding, trigger, context, onDismiss) {
4030
+ updateValidationsForBinding(binding, trigger, validationContext, onDismiss) {
3567
4031
  var _a;
4032
+ const context = validationContext != null ? validationContext : this.options;
4033
+ if (!context) {
4034
+ throw new Error(`Context is required for executing validations`);
4035
+ }
3568
4036
  if (trigger === "load") {
3569
- const possibleValidations = this.providers.reduce((vals, provider) => {
3570
- var _a2, _b;
4037
+ const possibleValidations = this.getValidationProviders().reduce((vals, provider) => {
4038
+ var _a2, _b, _c, _d;
3571
4039
  return [
3572
4040
  ...vals,
3573
- ...(_b = (_a2 = provider.getValidationsForBinding) == null ? void 0 : _a2.call(provider, binding)) != null ? _b : []
4041
+ ...(_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), {
4042
+ [VALIDATION_PROVIDER_NAME_SYMBOL]: provider.source
4043
+ }))) != null ? _d : []
3574
4044
  ];
3575
4045
  }, []);
3576
4046
  if (possibleValidations.length === 0) {
@@ -3580,7 +4050,7 @@ class ValidationController {
3580
4050
  }
3581
4051
  const trackedValidations = this.validations.get(binding);
3582
4052
  trackedValidations == null ? void 0 : trackedValidations.update(trigger, true, (validationObj) => {
3583
- const response = this.validationRunner(validationObj, context, binding);
4053
+ const response = this.validationRunner(validationObj, binding, context);
3584
4054
  if (this.weakBindingTracker.size > 0) {
3585
4055
  const t = this.validations.get(binding);
3586
4056
  this.weakBindingTracker.forEach((b) => t.weakBindings.add(b));
@@ -3591,27 +4061,33 @@ class ValidationController {
3591
4061
  this.validations.forEach((validation, vBinding) => {
3592
4062
  if (vBinding !== binding && caresAboutDataChanges(new Set([binding]), validation.weakBindings)) {
3593
4063
  validation.update(trigger, true, (validationObj) => {
3594
- const response = this.validationRunner(validationObj, context, binding);
4064
+ const response = this.validationRunner(validationObj, vBinding, context);
3595
4065
  return response ? { message: response.message } : void 0;
3596
4066
  });
3597
4067
  }
3598
4068
  });
3599
4069
  }
3600
4070
  }
3601
- validationRunner(validationObj, context, binding) {
3602
- const handler = this.getValidator(validationObj.type);
4071
+ validationRunner(validationObj, binding, context = this.options) {
4072
+ var _a;
4073
+ if (!context) {
4074
+ throw new Error("No context provided to validation runner");
4075
+ }
4076
+ const handler = (_a = validationObj.handler) != null ? _a : this.getValidator(validationObj.type);
3603
4077
  const weakBindings = new Set();
3604
4078
  const model = {
3605
- get(b, options = { includeInvalid: true }) {
4079
+ get(b, options) {
3606
4080
  weakBindings.add(isBinding(b) ? binding : context.parseBinding(b));
3607
- return context.model.get(b, options);
4081
+ return context.model.get(b, __spreadProps$2(__spreadValues$3({}, options), { includeInvalid: true }));
3608
4082
  },
3609
- set: context.model.set
4083
+ set: context.model.set,
4084
+ delete: context.model.delete
3610
4085
  };
3611
4086
  const result = handler == null ? void 0 : handler(__spreadProps$2(__spreadValues$3({}, context), {
3612
4087
  evaluate: (exp, options = { model }) => context.evaluate(exp, options),
3613
4088
  model,
3614
- validation: validationObj
4089
+ validation: validationObj,
4090
+ schemaType: this.schema.getType(binding)
3615
4091
  }), context.model.get(binding, {
3616
4092
  includeInvalid: true,
3617
4093
  formatted: validationObj.dataTarget === "formatted"
@@ -3635,29 +4111,27 @@ class ValidationController {
3635
4111
  }
3636
4112
  }
3637
4113
  updateValidationsForView(trigger) {
3638
- const { activeBindings } = this;
3639
- const canDismiss = trigger !== "navigation" || this.setCompare(this.lastActiveBindings, activeBindings);
3640
- this.getBindings().forEach((binding) => {
3641
- var _a;
3642
- (_a = this.validations.get(binding)) == null ? void 0 : _a.update(trigger, canDismiss, (obj) => {
3643
- if (!this.options) {
3644
- return;
3645
- }
3646
- return this.validationRunner(obj, this.options, binding);
4114
+ const isNavigationTrigger = trigger === "navigation";
4115
+ const lastActiveBindings = this.activeBindings;
4116
+ const updateValidations = (dismissValidations) => {
4117
+ this.getBindings().forEach((binding) => {
4118
+ var _a;
4119
+ (_a = this.validations.get(binding)) == null ? void 0 : _a.update(trigger, dismissValidations, (obj) => {
4120
+ if (!this.options) {
4121
+ return;
4122
+ }
4123
+ return this.validationRunner(obj, binding, this.options);
4124
+ });
3647
4125
  });
3648
- });
3649
- if (trigger === "navigation") {
3650
- this.lastActiveBindings = activeBindings;
4126
+ };
4127
+ updateValidations(!isNavigationTrigger);
4128
+ if (isNavigationTrigger) {
4129
+ const { activeBindings } = this;
4130
+ if (isSubset(activeBindings, lastActiveBindings)) {
4131
+ updateValidations(true);
4132
+ }
3651
4133
  }
3652
4134
  }
3653
- setCompare(set1, set2) {
3654
- if (set1.size !== set2.size)
3655
- return false;
3656
- for (const entry of set1)
3657
- if (!set2.has(entry))
3658
- return false;
3659
- return true;
3660
- }
3661
4135
  get activeBindings() {
3662
4136
  return new Set(Array.from(this.getBindings()).filter((b) => {
3663
4137
  var _a;
@@ -3677,19 +4151,30 @@ class ValidationController {
3677
4151
  var _a, _b;
3678
4152
  return (_b = (_a = this.tracker) == null ? void 0 : _a.getBindings()) != null ? _b : new Set();
3679
4153
  }
4154
+ trackBinding(binding) {
4155
+ var _a;
4156
+ (_a = this.tracker) == null ? void 0 : _a.trackBinding(binding);
4157
+ }
3680
4158
  validateView(trigger = "navigation") {
3681
- var _a, _b;
3682
4159
  this.updateValidationsForView(trigger);
3683
4160
  const validations = new Map();
3684
- for (const b of this.getBindings()) {
3685
- const invalid = (_a = this.getValidationForBinding(b)) == null ? void 0 : _a.get();
3686
- if (invalid) {
3687
- (_b = this.options) == null ? void 0 : _b.logger.debug(`Validation on binding: ${b.asString()} is preventing navigation. ${JSON.stringify(invalid)}`);
3688
- validations.set(b, invalid);
3689
- }
3690
- }
4161
+ let canTransition = true;
4162
+ this.getBindings().forEach((b) => {
4163
+ var _a;
4164
+ const allValidations = (_a = this.getValidationForBinding(b)) == null ? void 0 : _a.getAll();
4165
+ allValidations == null ? void 0 : allValidations.forEach((v) => {
4166
+ var _a2;
4167
+ if (trigger === "navigation" && v.blocking) {
4168
+ (_a2 = this.options) == null ? void 0 : _a2.logger.debug(`Validation on binding: ${b.asString()} is preventing navigation. ${JSON.stringify(v)}`);
4169
+ canTransition = false;
4170
+ }
4171
+ if (!validations.has(b)) {
4172
+ validations.set(b, v);
4173
+ }
4174
+ });
4175
+ });
3691
4176
  return {
3692
- canTransition: validations.size === 0,
4177
+ canTransition,
3693
4178
  validations: validations.size ? validations : void 0
3694
4179
  };
3695
4180
  }
@@ -3699,8 +4184,7 @@ class ValidationController {
3699
4184
  forView(parser) {
3700
4185
  return {
3701
4186
  _getValidationForBinding: (binding) => {
3702
- var _a;
3703
- return (_a = this.getValidationForBinding(isBinding(binding) ? binding : parser(binding))) == null ? void 0 : _a.get();
4187
+ return this.getValidationForBinding(isBinding(binding) ? binding : parser(binding));
3704
4188
  },
3705
4189
  getAll: () => {
3706
4190
  const bindings = this.getBindings();
@@ -3720,6 +4204,9 @@ class ValidationController {
3720
4204
  get() {
3721
4205
  throw new Error("Error Access be provided by the view plugin");
3722
4206
  },
4207
+ getValidationsForBinding() {
4208
+ throw new Error("Error rollup should be provided by the view plugin");
4209
+ },
3723
4210
  getChildren() {
3724
4211
  throw new Error("Error rollup should be provided by the view plugin");
3725
4212
  },
@@ -3730,7 +4217,7 @@ class ValidationController {
3730
4217
  throw new Error("Tracking should be provided by the view plugin");
3731
4218
  },
3732
4219
  register: () => {
3733
- throw new Error("Section funcationality hould be provided by the view plugin");
4220
+ throw new Error("Section functionality should be provided by the view plugin");
3734
4221
  },
3735
4222
  type: (binding) => this.schema.getType(isBinding(binding) ? binding : parser(binding))
3736
4223
  };
@@ -3846,10 +4333,11 @@ class AssetTransformCorePlugin {
3846
4333
  };
3847
4334
  };
3848
4335
  resolver.hooks.beforeResolve.tap("asset-transform", (node, options) => {
4336
+ var _a;
3849
4337
  if (node && (node.type === "asset" || node.type === "view")) {
3850
4338
  const transform = this.registry.get(node.value);
3851
4339
  if (transform == null ? void 0 : transform.beforeResolve) {
3852
- const store = getStore(node, this.beforeResolveSymbol);
4340
+ const store = getStore((_a = options.node) != null ? _a : node, this.beforeResolveSymbol);
3853
4341
  return transform.beforeResolve(node, options, store);
3854
4342
  }
3855
4343
  }
@@ -3927,14 +4415,26 @@ class ViewController {
3927
4415
  }
3928
4416
  });
3929
4417
  });
3930
- options.model.hooks.onUpdate.tap("viewController", (updates) => {
4418
+ const update = (updates) => {
3931
4419
  if (this.currentView) {
3932
4420
  if (this.optimizeUpdates) {
3933
- this.queueUpdate(new Set(updates.map((t) => t.binding)));
4421
+ this.queueUpdate(updates);
3934
4422
  } else {
3935
4423
  this.currentView.update();
3936
4424
  }
3937
4425
  }
4426
+ };
4427
+ options.model.hooks.onUpdate.tap("viewController", (updates) => {
4428
+ update(new Set(updates.map((t) => t.binding)));
4429
+ });
4430
+ options.model.hooks.onDelete.tap("viewController", (binding) => {
4431
+ const parentBinding = binding.parent();
4432
+ const property = binding.key();
4433
+ if (typeof property === "number" && parentBinding) {
4434
+ update(new Set([parentBinding]));
4435
+ } else {
4436
+ update(new Set([binding]));
4437
+ }
3938
4438
  });
3939
4439
  }
3940
4440
  queueUpdate(bindings) {
@@ -3979,6 +4479,25 @@ class ViewController {
3979
4479
  }
3980
4480
  }
3981
4481
 
4482
+ class ReadOnlyDataController {
4483
+ constructor(controller, logger) {
4484
+ this.controller = controller;
4485
+ this.logger = logger;
4486
+ }
4487
+ get(binding, options) {
4488
+ return this.controller.get(binding, options);
4489
+ }
4490
+ set(transaction, options) {
4491
+ var _a;
4492
+ (_a = this.logger) == null ? void 0 : _a.error("Error: Tried to set in a read only instance of the DataController");
4493
+ return [];
4494
+ }
4495
+ delete(binding, options) {
4496
+ var _a;
4497
+ (_a = this.logger) == null ? void 0 : _a.error("Error: Tried to delete in a read only instance of the DataController");
4498
+ }
4499
+ }
4500
+
3982
4501
  class DataController {
3983
4502
  constructor(model, options) {
3984
4503
  this.hooks = {
@@ -4035,16 +4554,19 @@ class DataController {
4035
4554
  });
4036
4555
  }
4037
4556
  const setUpdates = normalizedTransaction.reduce((updates, [binding, newVal]) => {
4038
- var _a;
4557
+ var _a, _b;
4039
4558
  const oldVal = this.get(binding, { includeInvalid: true });
4040
- if (!dequal(oldVal, newVal)) {
4041
- updates.push({
4042
- binding,
4043
- newValue: newVal,
4044
- oldValue: oldVal
4045
- });
4559
+ const update = {
4560
+ binding,
4561
+ newValue: newVal,
4562
+ oldValue: oldVal
4563
+ };
4564
+ if (dequal(oldVal, newVal)) {
4565
+ (_a = this.logger) == null ? void 0 : _a.debug(`Skipping update for path: ${binding.asString()}. Value was unchanged: ${oldVal}`);
4566
+ } else {
4567
+ updates.push(update);
4568
+ (_b = this.logger) == null ? void 0 : _b.debug(`Setting path: ${binding.asString()} from: ${oldVal} to: ${newVal}`);
4046
4569
  }
4047
- (_a = this.logger) == null ? void 0 : _a.debug(`Setting path: ${binding.asString()} from: ${oldVal} to: ${newVal}`);
4048
4570
  return updates;
4049
4571
  }, []);
4050
4572
  const result = this.getModel().set(normalizedTransaction, options);
@@ -4058,15 +4580,15 @@ class DataController {
4058
4580
  });
4059
4581
  this.hooks.onSet.call(normalizedTransaction);
4060
4582
  if (setUpdates.length > 0) {
4061
- this.hooks.onUpdate.call(setUpdates);
4583
+ this.hooks.onUpdate.call(setUpdates, options);
4062
4584
  }
4063
4585
  return result;
4064
4586
  }
4065
- resolve(binding) {
4066
- return Array.isArray(binding) || typeof binding === "string" ? this.pathResolver.parse(binding) : binding;
4587
+ resolve(binding, readOnly) {
4588
+ return Array.isArray(binding) || typeof binding === "string" ? this.pathResolver.parse(binding, { readOnly }) : binding;
4067
4589
  }
4068
4590
  get(binding, options) {
4069
- const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding);
4591
+ const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding, true);
4070
4592
  let result = this.getModel().get(resolved, options);
4071
4593
  if (result === void 0 && !(options == null ? void 0 : options.ignoreDefaultValue)) {
4072
4594
  const defaultVal = this.hooks.resolveDefaultValue.call(resolved);
@@ -4076,48 +4598,33 @@ class DataController {
4076
4598
  }
4077
4599
  if (options == null ? void 0 : options.formatted) {
4078
4600
  result = this.hooks.format.call(result, resolved);
4601
+ } else if ((options == null ? void 0 : options.formatted) === false) {
4602
+ result = this.hooks.deformat.call(result, resolved);
4079
4603
  }
4080
4604
  this.hooks.onGet.call(binding, result);
4081
4605
  return result;
4082
4606
  }
4083
- delete(binding) {
4084
- if (binding === void 0 || binding === null) {
4085
- throw new Error(`Invalid arguments: delete expects a data path (string)`);
4607
+ delete(binding, options) {
4608
+ if (typeof binding !== "string" && !Array.isArray(binding) && !(binding instanceof BindingInstance)) {
4609
+ throw new Error("Invalid arguments: delete expects a data path (string)");
4086
4610
  }
4087
- const resolved = this.resolve(binding);
4088
- this.hooks.onDelete.call(resolved);
4089
- this.deleteData(resolved);
4090
- }
4091
- getTrash() {
4092
- return this.trash;
4093
- }
4094
- addToTrash(binding) {
4095
- this.trash.add(binding);
4096
- }
4097
- deleteData(binding) {
4098
- const parentBinding = binding.parent();
4099
- const parentPath = parentBinding.asString();
4100
- const property = binding.key();
4101
- const existedBeforeDelete = Object.prototype.hasOwnProperty.call(this.get(parentBinding), property);
4102
- if (property !== void 0) {
4103
- const parent = parentBinding ? this.get(parentBinding) : void 0;
4104
- if (parentPath && Array.isArray(parent)) {
4105
- if (parent.length > property) {
4106
- this.set([[parentBinding, removeAt(parent, property)]]);
4107
- }
4108
- } else if (parentPath && parent[property]) {
4109
- this.set([[parentBinding, omit(parent, property)]]);
4110
- } else if (!parentPath) {
4111
- this.getModel().reset(omit(this.get(""), property));
4112
- }
4113
- }
4114
- if (existedBeforeDelete && !this.get(binding)) {
4115
- this.addToTrash(binding);
4611
+ const resolved = binding instanceof BindingInstance ? binding : this.resolve(binding, false);
4612
+ const parentBinding = resolved.parent();
4613
+ const property = resolved.key();
4614
+ const parentValue = this.get(parentBinding);
4615
+ const existedBeforeDelete = typeof parentValue === "object" && parentValue !== null && Object.prototype.hasOwnProperty.call(parentValue, property);
4616
+ this.getModel().delete(resolved, options);
4617
+ if (existedBeforeDelete && !this.get(resolved)) {
4618
+ this.trash.add(resolved);
4116
4619
  }
4620
+ this.hooks.onDelete.call(resolved);
4117
4621
  }
4118
4622
  serialize() {
4119
4623
  return this.hooks.serialize.call(this.get(""));
4120
4624
  }
4625
+ makeReadOnly() {
4626
+ return new ReadOnlyDataController(this, this.logger);
4627
+ }
4121
4628
  }
4122
4629
 
4123
4630
  var __defProp$1 = Object.defineProperty;
@@ -4174,10 +4681,15 @@ class ConstantsController {
4174
4681
  this.tempStore.set(namespace, new LocalModel(data));
4175
4682
  }
4176
4683
  }
4177
- clearTemporaryValues() {
4178
- this.tempStore.forEach((value) => {
4179
- value.reset();
4180
- });
4684
+ clearTemporaryValues(namespace) {
4685
+ var _a;
4686
+ if (namespace) {
4687
+ (_a = this.tempStore.get(namespace)) == null ? void 0 : _a.reset();
4688
+ } else {
4689
+ this.tempStore.forEach((value) => {
4690
+ value.reset();
4691
+ });
4692
+ }
4181
4693
  }
4182
4694
  }
4183
4695
 
@@ -4215,6 +4727,39 @@ class FlowExpPlugin {
4215
4727
  }
4216
4728
  }
4217
4729
 
4730
+ const createFormatFunction = (schema) => {
4731
+ const handler = (ctx, value, formatName) => {
4732
+ var _a, _b;
4733
+ return (_b = (_a = schema.getFormatterForType({ type: formatName })) == null ? void 0 : _a.format(value)) != null ? _b : value;
4734
+ };
4735
+ return handler;
4736
+ };
4737
+ class DefaultExpPlugin {
4738
+ constructor() {
4739
+ this.name = "flow-exp-plugin";
4740
+ }
4741
+ apply(player) {
4742
+ let formatFunction;
4743
+ player.hooks.schema.tap(this.name, (schemaController) => {
4744
+ formatFunction = createFormatFunction(schemaController);
4745
+ });
4746
+ player.hooks.expressionEvaluator.tap(this.name, (expEvaluator) => {
4747
+ if (formatFunction) {
4748
+ expEvaluator.addExpressionFunction("format", formatFunction);
4749
+ }
4750
+ expEvaluator.addExpressionFunction("log", (ctx, ...args) => {
4751
+ player.logger.info(...args);
4752
+ });
4753
+ expEvaluator.addExpressionFunction("debug", (ctx, ...args) => {
4754
+ player.logger.debug(...args);
4755
+ });
4756
+ expEvaluator.addExpressionFunction("eval", (ctx, ...args) => {
4757
+ return ctx.evaluate(...args);
4758
+ });
4759
+ });
4760
+ }
4761
+ }
4762
+
4218
4763
  const NOT_STARTED_STATE = {
4219
4764
  ref: Symbol("not-started"),
4220
4765
  status: "not-started"
@@ -4259,8 +4804,8 @@ var __async = (__this, __arguments, generator) => {
4259
4804
  step((generator = generator.apply(__this, __arguments)).next());
4260
4805
  });
4261
4806
  };
4262
- const PLAYER_VERSION = "0.3.1-next.1";
4263
- const COMMIT = "b51603be07572111ca68e73d1b710ed2d0aa9412";
4807
+ const PLAYER_VERSION = "0.3.1";
4808
+ const COMMIT = "e8392cd5df3c84fb9c68daf149ea88c593ce0428";
4264
4809
  const _Player = class {
4265
4810
  constructor(config) {
4266
4811
  this.logger = new TapableLogger();
@@ -4281,14 +4826,15 @@ const _Player = class {
4281
4826
  resolveFlowContent: new SyncWaterfallHook()
4282
4827
  };
4283
4828
  var _a;
4284
- const initialPlugins = [];
4285
- const flowExpPlugin = new FlowExpPlugin();
4286
- initialPlugins.push(flowExpPlugin);
4287
4829
  if (config == null ? void 0 : config.logger) {
4288
4830
  this.logger.addHandler(config.logger);
4289
4831
  }
4290
4832
  this.config = config || {};
4291
- this.config.plugins = [...this.config.plugins || [], ...initialPlugins];
4833
+ this.config.plugins = [
4834
+ new DefaultExpPlugin(),
4835
+ ...this.config.plugins || [],
4836
+ new FlowExpPlugin()
4837
+ ];
4292
4838
  (_a = this.config.plugins) == null ? void 0 : _a.forEach((plugin) => {
4293
4839
  plugin.apply(this);
4294
4840
  });
@@ -4379,25 +4925,27 @@ const _Player = class {
4379
4925
  flowResultDeferred.reject(e);
4380
4926
  return true;
4381
4927
  });
4382
- function resolveStrings(val) {
4928
+ function resolveStrings(val, formatted) {
4383
4929
  return resolveDataRefs(val, {
4384
4930
  model: dataController,
4385
- evaluate: expressionEvaluator.evaluate
4931
+ evaluate: expressionEvaluator.evaluate,
4932
+ formatted
4386
4933
  });
4387
4934
  }
4388
4935
  flowController.hooks.flow.tap("player", (flow) => {
4389
4936
  flow.hooks.beforeTransition.tap("player", (state, transitionVal) => {
4390
- if (state.onEnd && (state.transitions[transitionVal] || state.transitions["*"])) {
4937
+ const computedTransitionVal = state.transitions[transitionVal] ? transitionVal : "*";
4938
+ if (state.onEnd && state.transitions[computedTransitionVal]) {
4391
4939
  if (typeof state.onEnd === "object" && "exp" in state.onEnd) {
4392
4940
  expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(state.onEnd.exp);
4393
4941
  } else {
4394
4942
  expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(state.onEnd);
4395
4943
  }
4396
4944
  }
4397
- if (!("transitions" in state) || !state.transitions[transitionVal]) {
4945
+ if (!("transitions" in state) || !state.transitions[computedTransitionVal]) {
4398
4946
  return state;
4399
4947
  }
4400
- return setIn(state, ["transitions", transitionVal], resolveStrings(state.transitions[transitionVal]));
4948
+ return setIn(state, ["transitions", computedTransitionVal], resolveStrings(state.transitions[computedTransitionVal]));
4401
4949
  });
4402
4950
  flow.hooks.skipTransition.tap("validation", (currentState) => {
4403
4951
  var _a;
@@ -4417,16 +4965,21 @@ const _Player = class {
4417
4965
  newState = setIn(state, ["ref"], resolveStrings(state.ref));
4418
4966
  }
4419
4967
  if ("param" in state) {
4420
- newState = setIn(state, ["param"], resolveStrings(state.param));
4968
+ newState = setIn(state, ["param"], resolveStrings(state.param, false));
4421
4969
  }
4422
4970
  return newState;
4423
4971
  });
4424
4972
  flow.hooks.transition.tap("player", (_oldState, newState) => {
4425
- if (newState.value.state_type === "ACTION") {
4426
- const { exp } = newState.value;
4427
- queueMicrotask(() => {
4428
- flowController == null ? void 0 : flowController.transition(String(expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(exp)));
4429
- });
4973
+ if (newState.value.state_type !== "VIEW") {
4974
+ validationController.reset();
4975
+ }
4976
+ });
4977
+ flow.hooks.afterTransition.tap("player", (flowInstance) => {
4978
+ var _a;
4979
+ const value = (_a = flowInstance.currentState) == null ? void 0 : _a.value;
4980
+ if (value && value.state_type === "ACTION") {
4981
+ const { exp } = value;
4982
+ flowController == null ? void 0 : flowController.transition(String(expressionEvaluator == null ? void 0 : expressionEvaluator.evaluate(exp)));
4430
4983
  }
4431
4984
  expressionEvaluator.reset();
4432
4985
  });
@@ -4444,6 +4997,11 @@ const _Player = class {
4444
4997
  parseBinding,
4445
4998
  transition: flowController.transition,
4446
4999
  model: dataController,
5000
+ utils: {
5001
+ findPlugin: (pluginSymbol) => {
5002
+ return this.findPlugin(pluginSymbol);
5003
+ }
5004
+ },
4447
5005
  logger: this.logger,
4448
5006
  flowController,
4449
5007
  schema,
@@ -4457,23 +5015,19 @@ const _Player = class {
4457
5015
  },
4458
5016
  validation: __spreadProps(__spreadValues({}, validationController.forView(parseBinding)), {
4459
5017
  type: (b) => schema.getType(parseBinding(b))
4460
- })
5018
+ }),
5019
+ constants: this.constantsController
4461
5020
  });
4462
5021
  viewController.hooks.view.tap("player", (view) => {
4463
5022
  validationController.onView(view);
4464
5023
  this.hooks.view.call(view);
4465
5024
  });
4466
5025
  this.hooks.viewController.call(viewController);
4467
- const formatFunction = (ctx, value, formatName) => {
4468
- var _a, _b;
4469
- return (_b = (_a = schema.getFormatterForType({ type: formatName })) == null ? void 0 : _a.format(value)) != null ? _b : value;
4470
- };
4471
- expressionEvaluator.addExpressionFunction("format", formatFunction);
4472
5026
  return {
4473
5027
  start: () => {
4474
5028
  flowController.start().then((endState) => {
4475
5029
  const flowResult = {
4476
- endState: resolveStrings(endState),
5030
+ endState: resolveStrings(endState, false),
4477
5031
  data: dataController.serialize()
4478
5032
  };
4479
5033
  return flowResult;
@@ -4526,7 +5080,9 @@ const _Player = class {
4526
5080
  ref,
4527
5081
  status: "completed",
4528
5082
  flow: state.flow,
4529
- dataModel: state.controllers.data.getModel()
5083
+ controllers: {
5084
+ data: state.controllers.data.makeReadOnly()
5085
+ }
4530
5086
  };
4531
5087
  return maybeUpdateState(__spreadValues(__spreadValues({}, yield state.flowResult), endProps));
4532
5088
  } catch (error) {
@@ -4548,5 +5104,5 @@ Player.info = {
4548
5104
  commit: COMMIT
4549
5105
  };
4550
5106
 
4551
- export { ApplicabilityPlugin, AssetTransformCorePlugin, BindingInstance, BindingParser, Builder, ConsoleLogger, ConstantsController, DataController, DependencyMiddleware, DependencyModel, DependencyTracker, EMPTY_NODE, ExpNodeOpaqueIdentifier, ExpressionEvaluator, FlowController, FlowExpPlugin, FlowInstance, LocalModel, LocalStateStore, NOOPDataModel, NOOP_MODEL, NOT_STARTED_STATE, NodeType, NoopLogger, Parser, PipelinedDataModel, Player, ProxyLogger, ROOT_BINDING, Resolver, SIMPLE_BINDING_REGEX, SchemaController, StringResolverPlugin, SwitchPlugin, TapableLogger, TemplatePlugin, ValidationBindingTrackerViewPlugin, ValidationController, ValidationMiddleware, ValidatorRegistry, ViewController, ViewInstance, caresAboutDataChanges, constructModelForPipeline, findInArray, findNextExp, getBindingSegments, isBinding, isExpressionNode, maybeConvertToNum, parse, resolveDataRefs, resolveDataRefsInString, resolveExpressionsInString, severities, toModel, toNodeResolveOptions, withParser, withoutContext };
5107
+ export { ApplicabilityPlugin, AssetTransformCorePlugin, BINDING_BRACKETS_REGEX, BindingInstance, BindingParser, Builder, ConsoleLogger, ConstantsController, DataController, DependencyMiddleware, DependencyModel, DependencyTracker, EMPTY_NODE, ExpNodeOpaqueIdentifier, ExpressionEvaluator, FlowController, FlowExpPlugin, FlowInstance, LocalModel, LocalStateStore, NOOPDataModel, NOOP_MODEL, NOT_STARTED_STATE, NodeType, NoopLogger, Parser, PipelinedDataModel, Player, ProxyLogger, ROOT_BINDING, Resolver, SCHEMA_VALIDATION_PROVIDER_NAME, SIMPLE_BINDING_REGEX, SchemaController, StringResolverPlugin, SwitchPlugin, TapableLogger, TemplatePlugin, VALIDATION_PROVIDER_NAME_SYMBOL, VIEW_VALIDATION_PROVIDER_NAME, ValidationBindingTrackerViewPlugin, ValidationController, ValidationMiddleware, ValidatorRegistry, ViewController, ViewInstance, caresAboutDataChanges, constructModelForPipeline, findClosestNodeAtPosition, findInArray, findNextExp, getBindingSegments, isBinding, isExpressionNode, isObjectExpression, maybeConvertToNum, parse, parseExpression, removeBindingAndChildrenFromMap, resolveDataRefs, resolveDataRefsInString, resolveExpressionsInString, severities, toModel, toNodeResolveOptions, withParser, withoutContext };
4552
5108
  //# sourceMappingURL=index.esm.js.map