littlewing 2.3.1 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -760,7 +760,7 @@ declare const defaultContext: ExecutionContext;
760
760
  * Note: PlainDateTime check must precede PlainDate because PlainDateTime is not an
761
761
  * instance of PlainDate in the Temporal API, but ordering is kept explicit for clarity.
762
762
  */
763
- declare function typeOf(value: RuntimeValue): string;
763
+ declare function typeOf(value: unknown): string;
764
764
  /**
765
765
  * Assert a value is a number, throwing a TypeError if not
766
766
  */
package/dist/index.js CHANGED
@@ -740,21 +740,25 @@ function lexIdentifier(cursor) {
740
740
 
741
741
  // src/utils.ts
742
742
  function typeOf(value) {
743
+ if (value === undefined)
744
+ return "undefined";
745
+ if (value === null)
746
+ return "null";
743
747
  if (typeof value === "number")
744
748
  return "number";
745
749
  if (typeof value === "string")
746
750
  return "string";
747
751
  if (typeof value === "boolean")
748
752
  return "boolean";
753
+ if (Array.isArray(value))
754
+ return "array";
749
755
  if (value instanceof Temporal.PlainDateTime)
750
756
  return "datetime";
751
757
  if (value instanceof Temporal.PlainDate)
752
758
  return "date";
753
759
  if (value instanceof Temporal.PlainTime)
754
760
  return "time";
755
- if (Array.isArray(value))
756
- return "array";
757
- throw new Error(`Unknown runtime value type`);
761
+ return typeof value;
758
762
  }
759
763
  function deepEquals(a, b) {
760
764
  if (typeof a === "number" && typeof b === "number")
@@ -791,6 +795,13 @@ function assertNumber(v, context, side) {
791
795
  throw new TypeError(`${context}${where} expected number, got ${typeOf(v)}`);
792
796
  }
793
797
  }
798
+ function assertInteger(v, context, side) {
799
+ assertNumber(v, context, side);
800
+ if (!Number.isInteger(v)) {
801
+ const where = side ? ` (${side})` : "";
802
+ throw new TypeError(`${context}${where} expected integer, got ${v}`);
803
+ }
804
+ }
794
805
  function assertBoolean(v, context, side) {
795
806
  if (typeof v !== "boolean") {
796
807
  const where = side ? ` (${side})` : "";
@@ -2308,6 +2319,30 @@ function fold(node) {
2308
2319
  }
2309
2320
  case 3 /* BinaryOp */: {
2310
2321
  const left = recurse(node.left);
2322
+ if (node.operator === "&&") {
2323
+ if (isBooleanLiteral(left) && !left.value) {
2324
+ return preserveComments(node, boolean(false));
2325
+ }
2326
+ const right2 = recurse(node.right);
2327
+ if (isBooleanLiteral(left) && isBooleanLiteral(right2)) {
2328
+ return preserveComments(node, boolean(right2.value));
2329
+ }
2330
+ if (left === node.left && right2 === node.right)
2331
+ return node;
2332
+ return preserveComments(node, binaryOp(left, node.operator, right2));
2333
+ }
2334
+ if (node.operator === "||") {
2335
+ if (isBooleanLiteral(left) && left.value) {
2336
+ return preserveComments(node, boolean(true));
2337
+ }
2338
+ const right2 = recurse(node.right);
2339
+ if (isBooleanLiteral(left) && isBooleanLiteral(right2)) {
2340
+ return preserveComments(node, boolean(right2.value));
2341
+ }
2342
+ if (left === node.left && right2 === node.right)
2343
+ return node;
2344
+ return preserveComments(node, binaryOp(left, node.operator, right2));
2345
+ }
2311
2346
  const right = recurse(node.right);
2312
2347
  if (isNumberLiteral(left) && isNumberLiteral(right)) {
2313
2348
  const result = evaluateBinaryOperation(node.operator, left.value, right.value);
@@ -2329,10 +2364,6 @@ function fold(node) {
2329
2364
  return preserveComments(node, boolean(left.value !== right.value));
2330
2365
  }
2331
2366
  if (isBooleanLiteral(left) && isBooleanLiteral(right)) {
2332
- if (node.operator === "&&")
2333
- return preserveComments(node, boolean(left.value && right.value));
2334
- if (node.operator === "||")
2335
- return preserveComments(node, boolean(left.value || right.value));
2336
2367
  if (node.operator === "==")
2337
2368
  return preserveComments(node, boolean(left.value === right.value));
2338
2369
  if (node.operator === "!=")
@@ -2459,7 +2490,7 @@ __export(exports_array, {
2459
2490
  var ARR_SORT = (a) => {
2460
2491
  assertArray(a, "ARR_SORT");
2461
2492
  if (a.length <= 1)
2462
- return a;
2493
+ return [...a];
2463
2494
  const sorted = [...a];
2464
2495
  const elemType = typeOf(sorted[0]);
2465
2496
  sorted.sort((x, y) => {
@@ -2628,8 +2659,63 @@ function assertStringOrArray(v, context) {
2628
2659
  throw new TypeError(`${context} expected string or array, got ${typeOf(v)}`);
2629
2660
  }
2630
2661
  }
2662
+ function hasSurrogateCodeUnit(value) {
2663
+ for (let i = 0;i < value.length; i++) {
2664
+ const code = value.charCodeAt(i);
2665
+ if (code >= 55296 && code <= 57343)
2666
+ return true;
2667
+ }
2668
+ return false;
2669
+ }
2670
+ function codePointLength(value) {
2671
+ let length = 0;
2672
+ for (let i = 0;i < value.length; i++) {
2673
+ const code = value.charCodeAt(i);
2674
+ if (code >= 55296 && code <= 56319 && i + 1 < value.length) {
2675
+ const next = value.charCodeAt(i + 1);
2676
+ if (next >= 56320 && next <= 57343)
2677
+ i++;
2678
+ }
2679
+ length++;
2680
+ }
2681
+ return length;
2682
+ }
2683
+ function stringLength(value) {
2684
+ return hasSurrogateCodeUnit(value) ? codePointLength(value) : value.length;
2685
+ }
2686
+ function sliceString(value, start, end) {
2687
+ if (!hasSurrogateCodeUnit(value))
2688
+ return value.slice(start, end);
2689
+ return Array.from(value).slice(start, end).join("");
2690
+ }
2691
+ function indexOfString(value, search) {
2692
+ if (search === "")
2693
+ return 0;
2694
+ if (!hasSurrogateCodeUnit(value) && !hasSurrogateCodeUnit(search)) {
2695
+ return value.indexOf(search);
2696
+ }
2697
+ const haystack = Array.from(value);
2698
+ const needle = Array.from(search);
2699
+ if (needle.length > haystack.length)
2700
+ return -1;
2701
+ const limit = haystack.length - needle.length;
2702
+ for (let i = 0;i <= limit; i++) {
2703
+ let found = true;
2704
+ for (let j = 0;j < needle.length; j++) {
2705
+ if (haystack[i + j] !== needle[j]) {
2706
+ found = false;
2707
+ break;
2708
+ }
2709
+ }
2710
+ if (found)
2711
+ return i;
2712
+ }
2713
+ return -1;
2714
+ }
2631
2715
  var LEN = (v) => {
2632
2716
  assertStringOrArray(v, "LEN");
2717
+ if (typeof v === "string")
2718
+ return stringLength(v);
2633
2719
  return v.length;
2634
2720
  };
2635
2721
  var SLICE = (v, start, end) => {
@@ -2637,8 +2723,12 @@ var SLICE = (v, start, end) => {
2637
2723
  assertNumber(start, "SLICE", "start");
2638
2724
  if (end !== undefined) {
2639
2725
  assertNumber(end, "SLICE", "end");
2726
+ if (typeof v === "string")
2727
+ return sliceString(v, start, end);
2640
2728
  return v.slice(start, end);
2641
2729
  }
2730
+ if (typeof v === "string")
2731
+ return sliceString(v, start);
2642
2732
  return v.slice(start);
2643
2733
  };
2644
2734
  var CONTAINS = (v, search) => {
@@ -2664,7 +2754,7 @@ var INDEX_OF = (v, search) => {
2664
2754
  assertStringOrArray(v, "INDEX_OF");
2665
2755
  if (typeof v === "string") {
2666
2756
  assertString(search, "INDEX_OF (search)");
2667
- return v.indexOf(search);
2757
+ return indexOfString(v, search);
2668
2758
  }
2669
2759
  for (let i = 0;i < v.length; i++) {
2670
2760
  if (deepEquals(v[i], search))
@@ -2704,9 +2794,9 @@ __export(exports_datetime, {
2704
2794
  });
2705
2795
  var TODAY = () => Temporal.Now.plainDateISO();
2706
2796
  var DATE = (year, month, day) => {
2707
- assertNumber(year, "DATE", "year");
2708
- assertNumber(month, "DATE", "month");
2709
- assertNumber(day, "DATE", "day");
2797
+ assertInteger(year, "DATE", "year");
2798
+ assertInteger(month, "DATE", "month");
2799
+ assertInteger(day, "DATE", "day");
2710
2800
  return new Temporal.PlainDate(year, month, day);
2711
2801
  };
2712
2802
  var YEAR = (date) => {
@@ -2874,12 +2964,12 @@ __export(exports_datetimefull, {
2874
2964
  COMBINE: () => COMBINE
2875
2965
  });
2876
2966
  var DATETIME = (year, month, day, hour, minute, second) => {
2877
- assertNumber(year, "DATETIME", "year");
2878
- assertNumber(month, "DATETIME", "month");
2879
- assertNumber(day, "DATETIME", "day");
2880
- assertNumber(hour, "DATETIME", "hour");
2881
- assertNumber(minute, "DATETIME", "minute");
2882
- assertNumber(second, "DATETIME", "second");
2967
+ assertInteger(year, "DATETIME", "year");
2968
+ assertInteger(month, "DATETIME", "month");
2969
+ assertInteger(day, "DATETIME", "day");
2970
+ assertInteger(hour, "DATETIME", "hour");
2971
+ assertInteger(minute, "DATETIME", "minute");
2972
+ assertInteger(second, "DATETIME", "second");
2883
2973
  return new Temporal.PlainDateTime(year, month, day, hour, minute, second);
2884
2974
  };
2885
2975
  var NOW = () => Temporal.Now.plainDateTimeISO();
@@ -2958,12 +3048,18 @@ var SQRT = (x) => {
2958
3048
  return Math.sqrt(x);
2959
3049
  };
2960
3050
  var MIN = (...values) => {
3051
+ if (values.length === 0) {
3052
+ throw new RangeError("MIN requires at least one argument");
3053
+ }
2961
3054
  for (const value of values) {
2962
3055
  assertNumber(value, "MIN");
2963
3056
  }
2964
3057
  return Math.min(...values);
2965
3058
  };
2966
3059
  var MAX = (...values) => {
3060
+ if (values.length === 0) {
3061
+ throw new RangeError("MAX requires at least one argument");
3062
+ }
2967
3063
  for (const value of values) {
2968
3064
  assertNumber(value, "MAX");
2969
3065
  }
@@ -2997,6 +3093,9 @@ var CLAMP = (value, min, max) => {
2997
3093
  assertNumber(value, "CLAMP", "value");
2998
3094
  assertNumber(min, "CLAMP", "min");
2999
3095
  assertNumber(max, "CLAMP", "max");
3096
+ if (min > max) {
3097
+ throw new RangeError(`CLAMP: min (${min}) must not exceed max (${max})`);
3098
+ }
3000
3099
  return value < min ? min : value > max ? max : value;
3001
3100
  };
3002
3101
 
@@ -3072,9 +3171,9 @@ __export(exports_time, {
3072
3171
  ADD_HOURS: () => ADD_HOURS
3073
3172
  });
3074
3173
  var TIME = (hour, minute, second) => {
3075
- assertNumber(hour, "TIME", "hour");
3076
- assertNumber(minute, "TIME", "minute");
3077
- assertNumber(second, "TIME", "second");
3174
+ assertInteger(hour, "TIME", "hour");
3175
+ assertInteger(minute, "TIME", "minute");
3176
+ assertInteger(second, "TIME", "second");
3078
3177
  return new Temporal.PlainTime(hour, minute, second);
3079
3178
  };
3080
3179
  var NOW_TIME = () => Temporal.Now.plainTimeISO();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlewing",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "A minimal, high-performance multi-type expression language with lexer, parser, and interpreter. Optimized for browsers with type-safe execution.",
5
5
  "keywords": [
6
6
  "calculator",