ecma-evaluator 2.0.9 → 2.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -185,8 +185,6 @@ var mutableMethods = [
185
185
  "DataView.prototype.setFloat64",
186
186
  "DataView.prototype.setBigInt64",
187
187
  "DataView.prototype.setBigUint64",
188
- "Promise.prototype.catch",
189
- "Promise.prototype.finally",
190
188
  "Generator.prototype.next",
191
189
  "Generator.prototype.return",
192
190
  "Generator.prototype.throw",
@@ -221,7 +219,8 @@ var dangerousMethods = [
221
219
  "Object.getOwnPropertyDescriptors",
222
220
  "Object.getOwnPropertyNames",
223
221
  "Object.getOwnPropertySymbols",
224
- "Object.getOwnPropertyDescriptors"
222
+ "Error.captureStackTrace",
223
+ "Error.prepareStackTrace"
225
224
  ];
226
225
  mutableMethods.push("Object.prototype.__proto__");
227
226
  var blockedMethods = _to_consumable_array(mutableMethods).concat(_to_consumable_array(dangerousMethods));
@@ -268,6 +267,10 @@ var blockedGlobalBuiltIns = [
268
267
  "Reflect",
269
268
  "Atomics",
270
269
  "WebAssembly",
270
+ "SharedArrayBuffer",
271
+ "queueMicrotask",
272
+ "AbortSignal",
273
+ "Promise",
271
274
  "console",
272
275
  "Intl",
273
276
  "Deno"
@@ -363,14 +366,127 @@ var ERROR_MESSAGES = {
363
366
  IS_INVALID_SYNTAX: "{0} is not a valid syntax",
364
367
  IS_NOT_FUNCTION: "{0} is not a function",
365
368
  IS_NOT_DEFINED: "{0} is not defined",
366
- IS_NOT_ALLOWED: "{0} is not allowed"
369
+ IS_NOT_ALLOWED: "{0} is not allowed",
370
+ EXPRESSION_TOO_LONG: "Expression exceeds the maximum length of {0} characters"
367
371
  };
372
+ var DEFAULT_MAX_INPUT_LENGTH = 10000;
373
+ var MAX_CONFIGURABLE_INPUT_LENGTH = 100000;
374
+ var DEFAULT_MAX_EVALUATION_STEPS = 10000;
375
+ var MAX_CONFIGURABLE_EVALUATION_STEPS = 100000;
376
+ var MAX_ARRAY_LENGTH = 10000;
377
+ var MAX_BUFFER_BYTES = 1000000;
378
+ var MAX_STRING_LENGTH = 100000;
379
+ var MAX_DATA_NODES = 100000;
380
+ var MAX_BIGINT_EXPONENT = 256n;
381
+ var MAX_BIGINT_BITS = 65536;
382
+ var TYPED_ARRAY_CONSTRUCTORS = new Set([
383
+ Int8Array,
384
+ Uint8Array,
385
+ Uint8ClampedArray,
386
+ Int16Array,
387
+ Uint16Array,
388
+ Int32Array,
389
+ Uint32Array,
390
+ Float32Array,
391
+ Float64Array,
392
+ "function" == typeof BigInt64Array ? BigInt64Array : null,
393
+ "function" == typeof BigUint64Array ? BigUint64Array : null
394
+ ].filter(function(constructor) {
395
+ return "function" == typeof constructor;
396
+ }));
397
+ var NO_OBJECT = Symbol("no-object");
368
398
  var renderErrorMessage = function(template) {
369
399
  var context = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {};
370
400
  return template.replace(/{(\w+)}/g, function(_, key) {
371
401
  return String(context[key]);
372
402
  });
373
403
  };
404
+ function validateLimit(value, name, defaultValue, maximum) {
405
+ if (void 0 === value) return defaultValue;
406
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
407
+ return value;
408
+ }
409
+ function countLiteralMatches(value, search, all) {
410
+ if ("" === search) return all ? value.length + 1 : 1;
411
+ var count = 0;
412
+ var position = 0;
413
+ while(-1 !== (position = value.indexOf(search, position))){
414
+ count++;
415
+ if (!all) break;
416
+ position += search.length;
417
+ }
418
+ return count;
419
+ }
420
+ function assertBoundedData(value, label) {
421
+ var pending = [
422
+ value
423
+ ];
424
+ var seen = new WeakSet();
425
+ var dataSize = 0;
426
+ var dataNodes = 0;
427
+ var enqueueProperties = function(object) {
428
+ var keys = Object.keys(object);
429
+ if (pending.length + keys.length > MAX_DATA_NODES) throw new RangeError("".concat(label, " exceeds the maximum data node count"));
430
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
431
+ try {
432
+ for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
433
+ var key = _step.value;
434
+ dataSize += key.length;
435
+ var descriptor = Object.getOwnPropertyDescriptor(object, key);
436
+ if (!descriptor || !Object.hasOwn(descriptor, "value")) throw new TypeError("".concat(label, " cannot contain accessor properties"));
437
+ pending.push(descriptor.value);
438
+ }
439
+ } catch (err) {
440
+ _didIteratorError = true;
441
+ _iteratorError = err;
442
+ } finally{
443
+ try {
444
+ if (!_iteratorNormalCompletion && null != _iterator.return) _iterator.return();
445
+ } finally{
446
+ if (_didIteratorError) throw _iteratorError;
447
+ }
448
+ }
449
+ };
450
+ while(pending.length > 0){
451
+ var current = pending.pop();
452
+ dataNodes++;
453
+ if (dataNodes > MAX_DATA_NODES) throw new RangeError("".concat(label, " exceeds the maximum data node count"));
454
+ if ("string" == typeof current) {
455
+ if (current.length > MAX_STRING_LENGTH) throw new RangeError("".concat(label, " contains a string that exceeds the maximum length"));
456
+ dataSize += current.length + 8;
457
+ } else if (null === current || (void 0 === current ? "undefined" : _type_of(current)) !== "object" && "function" != typeof current) {
458
+ dataSize += 8;
459
+ continue;
460
+ } else {
461
+ if ("function" == typeof current || seen.has(current)) continue;
462
+ seen.add(current);
463
+ dataSize += 16;
464
+ if (_instanceof(current, ArrayBuffer) || ArrayBuffer.isView(current)) dataSize += current.byteLength;
465
+ else if (Array.isArray(current)) {
466
+ if (current.length > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains an array that exceeds the maximum length"));
467
+ dataSize += 8 * current.length;
468
+ enqueueProperties(current);
469
+ } else if (_instanceof(current, Map)) {
470
+ if (current.size > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains a map that exceeds the maximum size"));
471
+ dataSize += 16 * current.size;
472
+ Map.prototype.forEach.call(current, function(item, key) {
473
+ return pending.push(key, item);
474
+ });
475
+ } else if (_instanceof(current, Set)) {
476
+ if (current.size > MAX_ARRAY_LENGTH) throw new RangeError("".concat(label, " contains a set that exceeds the maximum size"));
477
+ dataSize += 8 * current.size;
478
+ Set.prototype.forEach.call(current, function(item) {
479
+ return pending.push(item);
480
+ });
481
+ } else enqueueProperties(current);
482
+ }
483
+ if (dataSize > MAX_BUFFER_BYTES) throw new RangeError("".concat(label, " exceeds the maximum data size"));
484
+ }
485
+ return {
486
+ dataSize: dataSize,
487
+ dataNodes: dataNodes
488
+ };
489
+ }
374
490
  var BINARY_OPERATION_MAP = {
375
491
  "+": function(a, b) {
376
492
  return a + b;
@@ -509,21 +625,35 @@ var getBlockedMethods = function() {
509
625
  var Evaluator_Evaluator = /*#__PURE__*/ function() {
510
626
  "use strict";
511
627
  function Evaluator() {
512
- var variables = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : Object.create(null);
628
+ var variables = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : Object.create(null), options = arguments.length > 1 ? arguments[1] : void 0;
513
629
  _class_call_check(this, Evaluator);
630
+ this.maxInputLength = validateLimit(null == options ? void 0 : options.maxInputLength, "maxInputLength", DEFAULT_MAX_INPUT_LENGTH, MAX_CONFIGURABLE_INPUT_LENGTH);
631
+ this.maxEvaluationSteps = validateLimit(null == options ? void 0 : options.maxEvaluationSteps, "maxEvaluationSteps", DEFAULT_MAX_EVALUATION_STEPS, MAX_CONFIGURABLE_EVALUATION_STEPS);
632
+ assertBoundedData(variables, "Evaluation context");
633
+ var clonedVariables = structuredClone(variables);
514
634
  this.scopes = [
515
- structuredClone(variables),
635
+ clonedVariables,
516
636
  createGlobalScope()
517
637
  ].filter(function(scope) {
518
638
  return null != scope;
519
639
  });
520
640
  this.source = void 0;
641
+ this.remainingEvaluationSteps = 0;
642
+ this.remainingDataSize = MAX_BUFFER_BYTES;
643
+ this.remainingDataNodes = MAX_DATA_NODES;
521
644
  }
522
645
  _create_class(Evaluator, [
523
646
  {
524
647
  key: "evaluate",
525
648
  value: function(expression) {
649
+ if ("string" != typeof expression) throw new TypeError("Expression must be a string");
650
+ if (expression.length > this.maxInputLength) throw new SyntaxError(renderErrorMessage(ERROR_MESSAGES.EXPRESSION_TOO_LONG, [
651
+ this.maxInputLength
652
+ ]));
526
653
  this.source = expression;
654
+ this.remainingEvaluationSteps = this.maxEvaluationSteps;
655
+ this.remainingDataSize = MAX_BUFFER_BYTES;
656
+ this.remainingDataNodes = MAX_DATA_NODES;
527
657
  var ast = external_acorn_namespaceObject.parse(expression, {
528
658
  ecmaVersion: "latest"
529
659
  });
@@ -537,6 +667,11 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
537
667
  {
538
668
  key: "execute",
539
669
  value: function(body) {
670
+ if (0 === this.remainingEvaluationSteps) {
671
+ this.remainingEvaluationSteps = this.maxEvaluationSteps;
672
+ this.remainingDataSize = MAX_BUFFER_BYTES;
673
+ this.remainingDataNodes = MAX_DATA_NODES;
674
+ }
540
675
  var result;
541
676
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
542
677
  try {
@@ -557,13 +692,26 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
557
692
  if ("function" == typeof result) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
558
693
  "Returning functions from expressions"
559
694
  ]));
560
- return result;
695
+ assertBoundedData(result, "Evaluation result");
696
+ if (_instanceof(result, Promise)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
697
+ "Returning promises from expressions"
698
+ ]));
699
+ try {
700
+ return structuredClone(result);
701
+ } catch (error) {
702
+ if (error && "DataCloneError" === error.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
703
+ "Returning non-cloneable values from expressions"
704
+ ]));
705
+ throw error;
706
+ }
561
707
  }
562
708
  },
563
709
  {
564
710
  key: "visit",
565
711
  value: function(node) {
566
712
  var _this = this;
713
+ this.remainingEvaluationSteps--;
714
+ if (this.remainingEvaluationSteps < 0) throw new RangeError("Evaluation step limit exceeded");
567
715
  switch(node.type){
568
716
  case "ExpressionStatement":
569
717
  return this.visit(node.expression);
@@ -600,10 +748,14 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
600
748
  if ("Function" === node.callee.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
601
749
  "new Function() constructor"
602
750
  ]));
751
+ if ("Promise" === node.callee.name) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
752
+ "Promise constructor"
753
+ ]));
603
754
  var Constructor = this.visit(node.callee);
604
755
  var args = node.arguments.length ? node.arguments.map(function(arg) {
605
756
  return _this.visit(arg);
606
757
  }) : [];
758
+ this.assertBoundedConstruction(Constructor, args);
607
759
  return _construct(Constructor, Evaluator_to_consumable_array(args));
608
760
  case "ChainExpression":
609
761
  return this.visit(node.expression);
@@ -632,10 +784,49 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
632
784
  var op = node.operator;
633
785
  var left = this.visit(node.left);
634
786
  var right = this.visit(node.right);
787
+ if ("+" === op && ("string" == typeof left || "string" == typeof right)) {
788
+ if (String(left).length + String(right).length > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
789
+ }
790
+ if ((void 0 === left ? "undefined" : _type_of(left)) === "bigint" && (void 0 === right ? "undefined" : _type_of(right)) === "bigint") {
791
+ if ("**" === op && (right > MAX_BIGINT_EXPONENT || right < 0n)) throw new RangeError("BigInt exponent must be between 0 and ".concat(MAX_BIGINT_EXPONENT));
792
+ var leftBits = left.toString(2).length;
793
+ var rightBits = right.toString(2).length;
794
+ if ("**" === op && leftBits * Number(right) > MAX_BIGINT_BITS || "<<" === op && right > BigInt(MAX_BIGINT_BITS) || "<<" === op && right >= 0n && leftBits + Number(right) > MAX_BIGINT_BITS || "*" === op && leftBits + rightBits > MAX_BIGINT_BITS || ("+" === op || "-" === op) && Math.max(leftBits, rightBits) + 1 > MAX_BIGINT_BITS) throw new RangeError("BigInt result exceeds the maximum allowed size");
795
+ }
635
796
  if (BINARY_OPERATION_MAP.hasOwnProperty(op)) return BINARY_OPERATION_MAP[op](left, right);
636
797
  throw new SyntaxError("Unsupported operator: ".concat(node.operator));
637
798
  }
638
799
  },
800
+ {
801
+ key: "assertBoundedConstruction",
802
+ value: function(Constructor, args) {
803
+ var _args_;
804
+ var size = args[0];
805
+ if (Constructor === Array && 1 === args.length && "number" == typeof size && size > MAX_ARRAY_LENGTH) throw new RangeError("Array length exceeds the maximum allowed length");
806
+ if (Constructor === ArrayBuffer && (size > MAX_BUFFER_BYTES || (null == (_args_ = args[1]) ? void 0 : _args_.maxByteLength) > MAX_BUFFER_BYTES)) throw new RangeError("ArrayBuffer size exceeds the maximum allowed size");
807
+ if (Constructor === DataView && _instanceof(size, ArrayBuffer) && size.byteLength > MAX_BUFFER_BYTES) throw new RangeError("DataView size exceeds the maximum allowed size");
808
+ if (Constructor === Map || Constructor === Set) {
809
+ var _size_size;
810
+ var collectionSize = "string" == typeof size || Array.isArray(size) ? size.length : null != (_size_size = null == size ? void 0 : size.size) ? _size_size : null == size ? void 0 : size.length;
811
+ if ("number" == typeof collectionSize && collectionSize > MAX_ARRAY_LENGTH) throw new RangeError("Collection source exceeds the maximum allowed size");
812
+ }
813
+ if (TYPED_ARRAY_CONSTRUCTORS.has(Constructor)) {
814
+ var byteLength;
815
+ if (_instanceof(size, ArrayBuffer)) {
816
+ var _args_1;
817
+ var offset = null != (_args_1 = args[1]) ? _args_1 : 0;
818
+ var _args_2;
819
+ var elementCount = null != (_args_2 = args[2]) ? _args_2 : Math.floor((size.byteLength - offset) / Constructor.BYTES_PER_ELEMENT);
820
+ byteLength = elementCount * Constructor.BYTES_PER_ELEMENT;
821
+ } else {
822
+ var _size_length;
823
+ var elementCount1 = "number" == typeof size ? size : null != (_size_length = null == size ? void 0 : size.length) ? _size_length : 0;
824
+ byteLength = elementCount1 * Constructor.BYTES_PER_ELEMENT;
825
+ }
826
+ if (byteLength > MAX_BUFFER_BYTES) throw new RangeError("Typed array size exceeds the maximum allowed size");
827
+ }
828
+ }
829
+ },
639
830
  {
640
831
  key: "handleLogicalExpression",
641
832
  value: function(node) {
@@ -707,9 +898,13 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
707
898
  {
708
899
  key: "handleMemberExpression",
709
900
  value: function(node) {
710
- var object = this.visit(node.object);
901
+ var objectValue = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : NO_OBJECT;
902
+ var object = objectValue === NO_OBJECT ? this.visit(node.object) : objectValue;
711
903
  var isStaticProperty = "Identifier" === node.property.type && !node.computed;
712
904
  var property = isStaticProperty ? node.property.name : this.visit(node.property);
905
+ if ("stack" === property && _instanceof(object, Error)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
906
+ "Accessing error stack"
907
+ ]));
713
908
  if (null != object && object[property] === (null == object ? void 0 : object.__proto__)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
714
909
  "Accessing prototype properties"
715
910
  ]));
@@ -733,30 +928,52 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
733
928
  var result = [];
734
929
  for(var i = 0; i < node.elements.length; i++){
735
930
  var element = node.elements.at(i);
931
+ if (null === element) {
932
+ result.length++;
933
+ continue;
934
+ }
736
935
  var value = this.visit(element);
737
936
  if ("SpreadElement" === element.type) {
738
937
  var _result;
938
+ this.assertBoundedSpread(result.length, value);
739
939
  (_result = result).push.apply(_result, Evaluator_to_consumable_array(value));
740
940
  } else result.push(value);
741
941
  }
742
942
  return result;
743
943
  }
744
944
  },
945
+ {
946
+ key: "assertBoundedSpread",
947
+ value: function(currentLength, value) {
948
+ var size = "string" == typeof value || Array.isArray(value) ? value.length : null == value ? void 0 : value.size;
949
+ if ("number" == typeof size && currentLength + size > MAX_ARRAY_LENGTH) throw new RangeError("Spread value exceeds the maximum allowed length");
950
+ }
951
+ },
745
952
  {
746
953
  key: "handleObjectExpression",
747
954
  value: function(node) {
748
955
  var obj = {};
956
+ var spreadPropertyCount = 0;
749
957
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
750
958
  try {
751
959
  for(var _iterator = node.properties[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
752
960
  var prop = _step.value;
753
961
  if ("SpreadElement" === prop.type) {
754
- Object.assign(obj, this.visit(prop.argument));
962
+ var spreadValue = this.visit(prop.argument);
963
+ spreadPropertyCount += Object.keys(spreadValue).length;
964
+ if (spreadPropertyCount > MAX_ARRAY_LENGTH) throw new RangeError("Object spread exceeds the maximum allowed property count");
965
+ Object.assign(obj, spreadValue);
755
966
  continue;
756
967
  }
757
- var key = prop.key.name || prop.key.value;
968
+ var key = prop.computed ? this.visit(prop.key) : prop.key.name || prop.key.value;
758
969
  var value = this.visit(prop.value);
759
- obj[key] = value;
970
+ if (prop.computed) Object.defineProperty(obj, key, {
971
+ value: value,
972
+ writable: true,
973
+ enumerable: true,
974
+ configurable: true
975
+ });
976
+ else obj[key] = value;
760
977
  }
761
978
  } catch (err) {
762
979
  _didIteratorError = true;
@@ -787,22 +1004,43 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
787
1004
  var paramCount = node.params.length;
788
1005
  for(var i = 0; i < paramCount; i++)newScope[node.params[i].name] = args[i];
789
1006
  _this.scopes.unshift(newScope);
790
- var result = _this.visit(node.body);
791
- _this.scopes.shift();
792
- return result;
1007
+ try {
1008
+ var result = _this.visit(node.body);
1009
+ _this.consumeEvaluationValue(result);
1010
+ return result;
1011
+ } finally{
1012
+ _this.scopes.shift();
1013
+ }
793
1014
  };
794
1015
  }
795
1016
  },
1017
+ {
1018
+ key: "consumeEvaluationValue",
1019
+ value: function(value) {
1020
+ var _assertBoundedData = assertBoundedData(value, "Intermediate evaluation result"), dataSize = _assertBoundedData.dataSize, dataNodes = _assertBoundedData.dataNodes;
1021
+ this.remainingDataSize -= dataSize;
1022
+ this.remainingDataNodes -= dataNodes;
1023
+ if (this.remainingDataSize < 0 || this.remainingDataNodes < 0) throw new RangeError("Evaluation allocation budget exceeded");
1024
+ }
1025
+ },
796
1026
  {
797
1027
  key: "handleCallExpression",
798
1028
  value: function(node) {
799
1029
  var _this = this;
800
- var func = this.visit(node.callee);
801
- var isOptional = node.optional || node.callee.optional;
1030
+ var isOptional = node.optional || "MemberExpression" === node.callee.type && node.callee.optional;
1031
+ var func;
1032
+ var target = null;
1033
+ if ("MemberExpression" === node.callee.type) {
1034
+ target = this.visit(node.callee.object);
1035
+ func = this.handleMemberExpression(node.callee, target);
1036
+ } else func = this.visit(node.callee);
802
1037
  if (null == func && isOptional) return;
803
1038
  if (func === Function) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
804
1039
  "Function constructor"
805
1040
  ]));
1041
+ if (func === Error.prepareStackTrace) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
1042
+ "Error.prepareStackTrace"
1043
+ ]));
806
1044
  if (getBlockedMethods().has(func)) {
807
1045
  var path = getBlockedMethods().get(func);
808
1046
  throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
@@ -817,24 +1055,56 @@ var Evaluator_Evaluator = /*#__PURE__*/ function() {
817
1055
  var value = _this.visit(element);
818
1056
  if ("SpreadElement" === element.type) {
819
1057
  var _result;
1058
+ _this.assertBoundedSpread(result.length, value);
820
1059
  (_result = result).push.apply(_result, Evaluator_to_consumable_array(value));
821
1060
  } else result.push(value);
822
1061
  }
823
1062
  return result;
824
1063
  }();
825
- var target = "MemberExpression" === node.callee.type ? this.visit(node.callee.object) : null;
826
1064
  if (args.some(function(arg) {
827
1065
  return arg === Function;
828
1066
  })) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
829
1067
  "Function constructor"
830
1068
  ]));
1069
+ if ("string" == typeof target) {
1070
+ if (String.prototype.repeat && func === String.prototype.repeat && target.length * Number(args[0]) > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1071
+ if ((String.prototype.padStart && func === String.prototype.padStart || func === String.prototype.padEnd) && Number(args[0]) > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1072
+ if (String.prototype.concat && func === String.prototype.concat) {
1073
+ var resultLength = target.length + args.reduce(function(length, value) {
1074
+ return length + String(value).length;
1075
+ }, 0);
1076
+ if (resultLength > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1077
+ }
1078
+ if (String.prototype.replace && func === String.prototype.replace || String.prototype.replaceAll && func === String.prototype.replaceAll) {
1079
+ if ("string" == typeof args[0]) {
1080
+ if ("function" == typeof args[1] || "string" == typeof args[1] && RegExp("\\$(?:[$&'`])", "u").test(args[1])) throw new Error("Only literal string replacements are allowed");
1081
+ if (target.length * Math.max(1, args[0].length) > 10000000) throw new RangeError("String operation exceeds the maximum work limit");
1082
+ var matchCount = countLiteralMatches(target, args[0], func === String.prototype.replaceAll);
1083
+ if (target.length + matchCount * String(args[1]).length > MAX_STRING_LENGTH) throw new RangeError("String result exceeds the maximum allowed length");
1084
+ }
1085
+ }
1086
+ if (func === String.prototype.split) {
1087
+ if ("" === args[0] && target.length > MAX_ARRAY_LENGTH) throw new RangeError("Split result exceeds the maximum allowed length");
1088
+ if ("string" == typeof args[0] && "" !== args[0] && countLiteralMatches(target, args[0], true) >= MAX_ARRAY_LENGTH) throw new RangeError("Split result exceeds the maximum allowed length");
1089
+ }
1090
+ }
1091
+ if ((target === Array || TYPED_ARRAY_CONSTRUCTORS.has(target)) && func === target.from) {
1092
+ var source = args[0];
1093
+ var _source_size;
1094
+ var size = "string" == typeof source || Array.isArray(source) ? source.length : null != (_source_size = null == source ? void 0 : source.size) ? _source_size : null == source ? void 0 : source.length;
1095
+ if ("number" == typeof size && size > MAX_ARRAY_LENGTH) throw new RangeError("Array.from source exceeds the maximum allowed length");
1096
+ }
831
1097
  if ("function" != typeof func) {
832
1098
  var calledString = getNodeString(node.callee);
833
1099
  throw new TypeError(renderErrorMessage(ERROR_MESSAGES.IS_NOT_FUNCTION, [
834
1100
  calledString
835
1101
  ]));
836
1102
  }
837
- return func.apply(target, args);
1103
+ var result = func.apply(target, args);
1104
+ if (_instanceof(result, Promise)) throw new Error(renderErrorMessage(ERROR_MESSAGES.IS_NOT_ALLOWED, [
1105
+ "Returning promises from expressions"
1106
+ ]));
1107
+ return result;
838
1108
  }
839
1109
  },
840
1110
  {
@@ -899,11 +1169,25 @@ function TemplateParser_create_class(Constructor, protoProps, staticProps) {
899
1169
  if (staticProps) TemplateParser_defineProperties(Constructor, staticProps);
900
1170
  return Constructor;
901
1171
  }
1172
+ var DEFAULT_MAX_TEMPLATE_LENGTH = 100000;
1173
+ var MAX_CONFIGURABLE_TEMPLATE_LENGTH = 1000000;
1174
+ var DEFAULT_MAX_TOKENS = 1000;
1175
+ var MAX_CONFIGURABLE_TOKENS = 10000;
1176
+ function TemplateParser_validateLimit(value, name, defaultValue, maximum) {
1177
+ if (void 0 === value) return defaultValue;
1178
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
1179
+ return value;
1180
+ }
902
1181
  var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
903
1182
  "use strict";
904
1183
  function TemplateParser() {
905
1184
  var options = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
906
1185
  TemplateParser_class_call_check(this, TemplateParser);
1186
+ null != options || (options = {});
1187
+ this.maxTemplateLength = TemplateParser_validateLimit(options.maxTemplateLength, "maxTemplateLength", DEFAULT_MAX_TEMPLATE_LENGTH, MAX_CONFIGURABLE_TEMPLATE_LENGTH);
1188
+ this.maxTokens = TemplateParser_validateLimit(options.maxTokens, "maxTokens", DEFAULT_MAX_TOKENS, MAX_CONFIGURABLE_TOKENS);
1189
+ if (void 0 !== options.expressionStart && ("string" != typeof options.expressionStart || 0 === options.expressionStart.length || options.expressionStart.length > 128)) throw new TypeError("expressionStart must be a non-empty string of at most 128 characters");
1190
+ if (void 0 !== options.expressionEnd && ("string" != typeof options.expressionEnd || 0 === options.expressionEnd.length || options.expressionEnd.length > 128)) throw new TypeError("expressionEnd must be a non-empty string of at most 128 characters");
907
1191
  this.exprStart = options.expressionStart || "{{";
908
1192
  this.exprEnd = options.expressionEnd || "}}";
909
1193
  this.startLen = this.exprStart.length;
@@ -914,8 +1198,14 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
914
1198
  {
915
1199
  key: "parse",
916
1200
  value: function(template) {
1201
+ var _this = this;
917
1202
  if ("string" != typeof template) throw new TypeError("模板必须是字符串");
1203
+ if (template.length > this.maxTemplateLength) throw new RangeError("Template exceeds the maximum length of ".concat(this.maxTemplateLength, " characters"));
918
1204
  var tokens = [];
1205
+ var pushToken = function(token) {
1206
+ if (tokens.length >= _this.maxTokens) throw new RangeError("Template exceeds the maximum token count of ".concat(_this.maxTokens));
1207
+ tokens.push(token);
1208
+ };
919
1209
  var length = template.length;
920
1210
  var state = "TEXT";
921
1211
  var buffer = "";
@@ -928,7 +1218,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
928
1218
  case "TEXT":
929
1219
  if (this._isMatch(pos, template, this.exprStart)) {
930
1220
  if (buffer.length > 0) {
931
- tokens.push({
1221
+ pushToken({
932
1222
  type: "text",
933
1223
  value: buffer,
934
1224
  start: pos - buffer.length,
@@ -950,7 +1240,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
950
1240
  else if ("\\" === char) state = "'" === nextChar ? "ESCAPE_SQ" : '"' === nextChar ? "ESCAPE_DQ" : "`" === nextChar ? "ESCAPE_TEMPLATE" : "ESCAPE_EXPR";
951
1241
  else if (this._isMatch(pos, template, this.exprEnd)) {
952
1242
  var exprValue = this.preserveWhitespace ? buffer : buffer.trim();
953
- if (exprValue.length > 0) tokens.push({
1243
+ if (exprValue.length > 0) pushToken({
954
1244
  type: "expression",
955
1245
  value: exprValue,
956
1246
  start: exprStartPos,
@@ -999,7 +1289,7 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
999
1289
  }
1000
1290
  pos++;
1001
1291
  }
1002
- if (buffer.length > 0) if ("TEXT" === state) tokens.push({
1292
+ if (buffer.length > 0) if ("TEXT" === state) pushToken({
1003
1293
  type: "text",
1004
1294
  value: buffer,
1005
1295
  start: pos - buffer.length,
@@ -1007,13 +1297,12 @@ var TemplateParser_TemplateParser = /*#__PURE__*/ function() {
1007
1297
  });
1008
1298
  else {
1009
1299
  var incompleteExpr = this.exprStart + buffer;
1010
- tokens.push({
1300
+ pushToken({
1011
1301
  type: "text",
1012
1302
  value: incompleteExpr,
1013
1303
  start: exprStartPos,
1014
1304
  end: pos
1015
1305
  });
1016
- console.warn("警告:在位置 ".concat(exprStartPos, " 开始的表达式未正确结束"));
1017
1306
  }
1018
1307
  return tokens;
1019
1308
  }
@@ -1041,18 +1330,36 @@ function src_instanceof(left, right) {
1041
1330
  if (null != right && "undefined" != typeof Symbol && right[Symbol.hasInstance]) return !!right[Symbol.hasInstance](left);
1042
1331
  return left instanceof right;
1043
1332
  }
1333
+ var DEFAULT_MAX_TEMPLATE_EXPRESSIONS = 100;
1334
+ var MAX_TEMPLATE_EXPRESSIONS = 1000;
1335
+ var DEFAULT_MAX_TEMPLATE_OUTPUT_LENGTH = 100000;
1336
+ var MAX_TEMPLATE_OUTPUT_LENGTH = 1000000;
1337
+ function src_validateLimit(value, name, defaultValue, maximum) {
1338
+ if (void 0 === value) return defaultValue;
1339
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum) throw new RangeError("".concat(name, " must be an integer between 1 and ").concat(maximum));
1340
+ return value;
1341
+ }
1044
1342
  function evalExpression(expression, context) {
1045
1343
  return Evaluator_Evaluator.evaluate(expression, context);
1046
1344
  }
1047
1345
  function evalTemplate(template, context, templateParserOptions) {
1346
+ var options = null != templateParserOptions ? templateParserOptions : {};
1347
+ var maxExpressions = src_validateLimit(options.maxExpressions, "maxExpressions", DEFAULT_MAX_TEMPLATE_EXPRESSIONS, MAX_TEMPLATE_EXPRESSIONS);
1348
+ var maxOutputLength = src_validateLimit(options.maxOutputLength, "maxOutputLength", DEFAULT_MAX_TEMPLATE_OUTPUT_LENGTH, MAX_TEMPLATE_OUTPUT_LENGTH);
1349
+ var tokens = TemplateParser_TemplateParser.parse(template, options);
1048
1350
  var result = "";
1351
+ var expressionCount = 0;
1352
+ var evaluator = new Evaluator_Evaluator(context, {
1353
+ maxInputLength: options.maxExpressionLength,
1354
+ maxEvaluationSteps: options.maxEvaluationSteps
1355
+ });
1049
1356
  var typeHandler = {
1050
1357
  text: function(token) {
1051
1358
  return token.value;
1052
1359
  },
1053
1360
  expression: function(token) {
1054
1361
  try {
1055
- return Evaluator_Evaluator.evaluate(token.value, context);
1362
+ return evaluator.evaluate(token.value);
1056
1363
  } catch (error) {
1057
1364
  if (src_instanceof(error, ReferenceError) && error.message.endsWith("is not defined")) return "undefined";
1058
1365
  throw error;
@@ -1061,11 +1368,17 @@ function evalTemplate(template, context, templateParserOptions) {
1061
1368
  };
1062
1369
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
1063
1370
  try {
1064
- for(var _iterator = TemplateParser_TemplateParser.parse(template, templateParserOptions)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1371
+ for(var _iterator = tokens[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1065
1372
  var token = _step.value;
1066
1373
  var _typeHandler_token_type;
1067
1374
  var handler = null != (_typeHandler_token_type = typeHandler[token.type]) ? _typeHandler_token_type : typeHandler["text"];
1068
- result += handler(token);
1375
+ if ("expression" === token.type) {
1376
+ expressionCount++;
1377
+ if (expressionCount > maxExpressions) throw new RangeError("Template exceeds the maximum expression count of ".concat(maxExpressions));
1378
+ }
1379
+ var chunk = String(handler(token));
1380
+ if (result.length + chunk.length > maxOutputLength) throw new RangeError("Template output exceeds the maximum length of ".concat(maxOutputLength, " characters"));
1381
+ result += chunk;
1069
1382
  }
1070
1383
  } catch (err) {
1071
1384
  _didIteratorError = true;