@synnaxlabs/x 0.40.0 → 0.42.0

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 (203) hide show
  1. package/.turbo/turbo-build.log +33 -33
  2. package/dist/binary.cjs +1 -1
  3. package/dist/binary.js +2 -2
  4. package/dist/bounds-BQo7rvs9.cjs +1 -0
  5. package/dist/{bounds-azUOoVVR.js → bounds-Bn5_l4Z3.js} +84 -86
  6. package/dist/bounds.cjs +1 -1
  7. package/dist/bounds.js +1 -1
  8. package/dist/box-0YrQibkB.cjs +1 -0
  9. package/dist/box-Cc8IzcNo.js +205 -0
  10. package/dist/box.cjs +1 -1
  11. package/dist/box.js +1 -1
  12. package/dist/compare.cjs +1 -1
  13. package/dist/compare.js +1 -1
  14. package/dist/deep.cjs +1 -1
  15. package/dist/deep.js +66 -69
  16. package/dist/{dimensions-PWy5QZoM.cjs → dimensions-D2QGoNXO.cjs} +1 -1
  17. package/dist/dimensions.cjs +1 -1
  18. package/dist/{external-CvWr1nhS.cjs → external-DWQITF5_.cjs} +1 -1
  19. package/dist/index-BywOGO8U.js +1074 -0
  20. package/dist/index-CYYjI7Uf.cjs +1 -0
  21. package/dist/index-C_6NXBlg.cjs +3 -0
  22. package/dist/{index-BVC_8Cg9.js → index-QGplUHuy.js} +1 -1
  23. package/dist/index.cjs +3 -3
  24. package/dist/index.js +736 -240
  25. package/dist/location-BGl5Ddds.cjs +1 -0
  26. package/dist/{location-BuYbIFHD.js → location-C3aeu046.js} +16 -12
  27. package/dist/location.cjs +1 -1
  28. package/dist/location.js +1 -1
  29. package/dist/{position-DTrNGtrm.cjs → position-Cai5-wi1.cjs} +1 -1
  30. package/dist/{position-DemzGvAY.js → position-DIglP1l2.js} +2 -2
  31. package/dist/position.cjs +1 -1
  32. package/dist/position.js +1 -1
  33. package/dist/record.js +3 -1
  34. package/dist/{scale-DpJM6__6.cjs → scale-BtZINJ-A.cjs} +1 -1
  35. package/dist/{scale-C0EllH-1.js → scale-DfJe9755.js} +4 -4
  36. package/dist/scale.cjs +1 -1
  37. package/dist/scale.js +1 -1
  38. package/dist/{series-CXnO-P0V.js → series-B9JERcqi.js} +541 -474
  39. package/dist/series-DqJ6f97G.cjs +11 -0
  40. package/dist/spatial.cjs +1 -1
  41. package/dist/spatial.js +6 -6
  42. package/dist/src/binary/{encoder.d.ts → codec.d.ts} +14 -8
  43. package/dist/src/binary/codec.d.ts.map +1 -0
  44. package/dist/src/binary/codec.spec.d.ts +2 -0
  45. package/dist/src/binary/codec.spec.d.ts.map +1 -0
  46. package/dist/src/binary/index.d.ts +1 -1
  47. package/dist/src/binary/index.d.ts.map +1 -1
  48. package/dist/src/breaker/breaker.d.ts +14 -21
  49. package/dist/src/breaker/breaker.d.ts.map +1 -1
  50. package/dist/src/change/change.d.ts +5 -18
  51. package/dist/src/change/change.d.ts.map +1 -1
  52. package/dist/src/color/color.d.ts +126 -0
  53. package/dist/src/color/color.d.ts.map +1 -0
  54. package/dist/src/color/color.spec.d.ts +2 -0
  55. package/dist/src/color/color.spec.d.ts.map +1 -0
  56. package/dist/src/color/external.d.ts +5 -0
  57. package/dist/src/color/external.d.ts.map +1 -0
  58. package/dist/src/color/gradient.d.ts +18 -0
  59. package/dist/src/color/gradient.d.ts.map +1 -0
  60. package/dist/src/color/index.d.ts +2 -0
  61. package/dist/src/color/index.d.ts.map +1 -0
  62. package/dist/src/color/palette.d.ts +19 -0
  63. package/dist/src/color/palette.d.ts.map +1 -0
  64. package/dist/src/color/transformColorsToHex.d.ts +6 -0
  65. package/dist/src/color/transformColorsToHex.d.ts.map +1 -0
  66. package/dist/src/control/control.d.ts +69 -74
  67. package/dist/src/control/control.d.ts.map +1 -1
  68. package/dist/src/deep/merge.d.ts +1 -1
  69. package/dist/src/deep/merge.d.ts.map +1 -1
  70. package/dist/src/errors/errors.d.ts +127 -7
  71. package/dist/src/errors/errors.d.ts.map +1 -1
  72. package/dist/src/errors/errors.spec.d.ts +2 -0
  73. package/dist/src/errors/errors.spec.d.ts.map +1 -0
  74. package/dist/src/index.d.ts +5 -0
  75. package/dist/src/index.d.ts.map +1 -1
  76. package/dist/src/jsonrpc/jsonrpc.d.ts +10 -7
  77. package/dist/src/jsonrpc/jsonrpc.d.ts.map +1 -1
  78. package/dist/src/kv/types.d.ts +1 -7
  79. package/dist/src/kv/types.d.ts.map +1 -1
  80. package/dist/src/math/external.d.ts +3 -0
  81. package/dist/src/math/external.d.ts.map +1 -0
  82. package/dist/src/math/index.d.ts +1 -1
  83. package/dist/src/math/index.d.ts.map +1 -1
  84. package/dist/src/math/round.d.ts +40 -0
  85. package/dist/src/math/round.d.ts.map +1 -0
  86. package/dist/src/math/round.spec.d.ts +2 -0
  87. package/dist/src/math/round.spec.d.ts.map +1 -0
  88. package/dist/src/migrate/migrate.d.ts +1 -1
  89. package/dist/src/notation/index.d.ts +2 -0
  90. package/dist/src/notation/index.d.ts.map +1 -0
  91. package/dist/src/notation/notation.d.ts +37 -0
  92. package/dist/src/notation/notation.d.ts.map +1 -0
  93. package/dist/src/notation/notation.spec.d.ts +2 -0
  94. package/dist/src/notation/notation.spec.d.ts.map +1 -0
  95. package/dist/src/record.d.ts +2 -1
  96. package/dist/src/record.d.ts.map +1 -1
  97. package/dist/src/replace.d.ts +2 -0
  98. package/dist/src/replace.d.ts.map +1 -0
  99. package/dist/src/runtime/os.d.ts +9 -1
  100. package/dist/src/runtime/os.d.ts.map +1 -1
  101. package/dist/src/singleton/define.d.ts +9 -0
  102. package/dist/src/singleton/define.d.ts.map +1 -0
  103. package/dist/src/singleton/define.spec.d.ts +2 -0
  104. package/dist/src/singleton/define.spec.d.ts.map +1 -0
  105. package/dist/src/singleton/index.d.ts +2 -0
  106. package/dist/src/singleton/index.d.ts.map +1 -0
  107. package/dist/src/spatial/base.d.ts +74 -70
  108. package/dist/src/spatial/base.d.ts.map +1 -1
  109. package/dist/src/spatial/box/box.d.ts +22 -76
  110. package/dist/src/spatial/box/box.d.ts.map +1 -1
  111. package/dist/src/spatial/dimensions/dimensions.d.ts +5 -29
  112. package/dist/src/spatial/dimensions/dimensions.d.ts.map +1 -1
  113. package/dist/src/spatial/direction/direction.d.ts +9 -1
  114. package/dist/src/spatial/direction/direction.d.ts.map +1 -1
  115. package/dist/src/spatial/location/location.d.ts +45 -24
  116. package/dist/src/spatial/location/location.d.ts.map +1 -1
  117. package/dist/src/spatial/scale/scale.d.ts +12 -120
  118. package/dist/src/spatial/scale/scale.d.ts.map +1 -1
  119. package/dist/src/spatial/xy/xy.d.ts +15 -29
  120. package/dist/src/spatial/xy/xy.d.ts.map +1 -1
  121. package/dist/src/sync/index.d.ts +2 -0
  122. package/dist/src/sync/index.d.ts.map +1 -0
  123. package/dist/src/sync/mutex.d.ts +8 -0
  124. package/dist/src/sync/mutex.d.ts.map +1 -0
  125. package/dist/src/telem/gl.d.ts +4 -1
  126. package/dist/src/telem/gl.d.ts.map +1 -1
  127. package/dist/src/telem/series.d.ts +46 -125
  128. package/dist/src/telem/series.d.ts.map +1 -1
  129. package/dist/src/telem/telem.d.ts +102 -85
  130. package/dist/src/telem/telem.d.ts.map +1 -1
  131. package/dist/src/toArray.d.ts +1 -1
  132. package/dist/src/toArray.d.ts.map +1 -1
  133. package/dist/src/zod/util.d.ts.map +1 -1
  134. package/dist/telem.cjs +1 -1
  135. package/dist/telem.js +1 -1
  136. package/dist/toArray.cjs +1 -1
  137. package/dist/toArray.js +1 -1
  138. package/dist/{xy-DyQSETQZ.cjs → xy-B7065J2S.cjs} +1 -1
  139. package/dist/{xy-DHBO1dG_.js → xy-D_LqxaGt.js} +8 -4
  140. package/dist/xy.cjs +1 -1
  141. package/dist/xy.js +1 -1
  142. package/dist/zod.cjs +1 -1
  143. package/package.json +11 -8
  144. package/src/binary/codec.spec.ts +370 -0
  145. package/src/binary/{encoder.ts → codec.ts} +55 -11
  146. package/src/binary/index.ts +1 -1
  147. package/src/breaker/breaker.spec.ts +16 -25
  148. package/src/breaker/breaker.ts +36 -19
  149. package/src/color/color.spec.ts +673 -0
  150. package/src/color/color.ts +317 -0
  151. package/src/color/external.ts +13 -0
  152. package/src/color/gradient.ts +78 -0
  153. package/src/color/index.ts +10 -0
  154. package/src/color/palette.ts +28 -0
  155. package/src/color/transformColorsToHex.ts +30 -0
  156. package/src/control/control.ts +30 -22
  157. package/src/deep/merge.ts +2 -8
  158. package/src/errors/errors.spec.ts +152 -0
  159. package/src/errors/errors.ts +225 -10
  160. package/src/index.ts +5 -0
  161. package/src/jsonrpc/jsonrpc.ts +12 -8
  162. package/src/math/external.ts +11 -0
  163. package/src/math/index.ts +1 -1
  164. package/src/math/round.spec.ts +81 -0
  165. package/src/math/round.ts +68 -0
  166. package/src/migrate/migrate.ts +2 -2
  167. package/src/notation/index.ts +10 -0
  168. package/src/notation/notation.spec.ts +88 -0
  169. package/src/notation/notation.ts +61 -0
  170. package/src/primitive.ts +1 -1
  171. package/src/record.ts +5 -1
  172. package/src/replace.ts +1 -0
  173. package/src/singleton/define.spec.ts +93 -0
  174. package/src/singleton/define.ts +27 -0
  175. package/src/singleton/index.ts +10 -0
  176. package/src/spatial/box/box.spec.ts +3 -3
  177. package/src/spatial/box/box.ts +8 -0
  178. package/src/spatial/location/location.ts +4 -4
  179. package/src/spatial/position/position.spec.ts +10 -10
  180. package/src/spatial/xy/xy.spec.ts +8 -0
  181. package/src/spatial/xy/xy.ts +14 -0
  182. package/src/sync/index.ts +1 -0
  183. package/src/sync/mutex.ts +16 -0
  184. package/src/telem/series.spec.ts +71 -0
  185. package/src/telem/series.ts +69 -46
  186. package/src/telem/telem.spec.ts +151 -10
  187. package/src/telem/telem.ts +134 -73
  188. package/src/toArray.ts +2 -2
  189. package/src/zod/util.spec.ts +17 -1
  190. package/src/zod/util.ts +4 -2
  191. package/tsconfig.tsbuildinfo +1 -1
  192. package/dist/bounds-Dwq6ZFHm.cjs +0 -1
  193. package/dist/box-Bzya27QS.cjs +0 -1
  194. package/dist/box-DrsrRNSe.js +0 -201
  195. package/dist/index-BG3Scw3G.cjs +0 -1
  196. package/dist/index-C3QzbIwt.js +0 -101
  197. package/dist/index-CnclyYpG.cjs +0 -3
  198. package/dist/location-BgpQ3rN2.cjs +0 -1
  199. package/dist/series-BgoCtU71.cjs +0 -11
  200. package/dist/src/binary/encoder.d.ts.map +0 -1
  201. package/dist/src/binary/encoder.spec.d.ts +0 -2
  202. package/dist/src/binary/encoder.spec.d.ts.map +0 -1
  203. package/src/binary/encoder.spec.ts +0 -174
@@ -126,6 +126,17 @@ const nullArrayZ = z
126
126
 
127
127
  const NEW_LINE = 10;
128
128
 
129
+ type JSType = "string" | "number" | "bigint";
130
+
131
+ const checkAsType = (jsType: JSType, dataType: DataType) => {
132
+ if (jsType === "string" && !dataType.isVariable)
133
+ throw new Error(`cannot convert series of type ${dataType.toString()} to string`);
134
+ if (jsType === "number" && !dataType.isNumeric)
135
+ throw new Error(`cannot convert series of type ${dataType.toString()} to number`);
136
+ if (jsType === "bigint" && !dataType.usesBigInt)
137
+ throw new Error(`cannot convert series of type ${dataType.toString()} to bigint`);
138
+ };
139
+
129
140
  /**
130
141
  * Series is a strongly typed array of telemetry samples backed by an underlying binary
131
142
  * buffer.
@@ -147,7 +158,7 @@ export class Series<T extends TelemValue = TelemValue> {
147
158
  private readonly gl: GL;
148
159
  /** The underlying data. */
149
160
  private readonly _data: ArrayBuffer;
150
- readonly _timeRange?: TimeRange;
161
+ readonly timeRange: TimeRange = TimeRange.ZERO;
151
162
  readonly alignment: bigint = 0n;
152
163
  /** A cached minimum value. */
153
164
  private _cachedMin?: math.Numeric;
@@ -200,7 +211,7 @@ export class Series<T extends TelemValue = TelemValue> {
200
211
  this.sampleOffset = data_.sampleOffset;
201
212
  this.gl = data_.gl;
202
213
  this._data = data_._data;
203
- this._timeRange = data_._timeRange;
214
+ this.timeRange = data_.timeRange;
204
215
  this.alignment = data_.alignment;
205
216
  this._cachedMin = data_._cachedMin;
206
217
  this._cachedMax = data_._cachedMax;
@@ -276,7 +287,7 @@ export class Series<T extends TelemValue = TelemValue> {
276
287
  this.key = key;
277
288
  this.alignment = alignment;
278
289
  this.sampleOffset = sampleOffset ?? 0;
279
- this._timeRange = timeRange;
290
+ this.timeRange = timeRange ?? TimeRange.ZERO;
280
291
  this.gl = {
281
292
  control: null,
282
293
  buffer: null,
@@ -330,11 +341,13 @@ export class Series<T extends TelemValue = TelemValue> {
330
341
  }
331
342
 
332
343
  release(): void {
344
+ if (this._refCount <= 0) {
345
+ console.warn("attempted to release a series with a negative reference count");
346
+ return;
347
+ }
333
348
  this._refCount--;
334
349
  if (this._refCount === 0 && this.gl.control != null)
335
350
  this.maybeGarbageCollectGLBuffer(this.gl.control);
336
- else if (this._refCount < 0)
337
- throw new Error("cannot release an array with a negative reference count");
338
351
  }
339
352
 
340
353
  /**
@@ -434,12 +447,6 @@ export class Series<T extends TelemValue = TelemValue> {
434
447
  .map((s) => schema.parse(binary.JSON_CODEC.decodeString(s)));
435
448
  }
436
449
 
437
- /** @returns the time range of this array. */
438
- get timeRange(): TimeRange {
439
- if (this._timeRange == null) throw new Error("time range not set on series");
440
- return this._timeRange;
441
- }
442
-
443
450
  /** @returns the capacity of the series in bytes. */
444
451
  get byteCapacity(): Size {
445
452
  return new Size(this.underlyingData.byteLength);
@@ -498,7 +505,7 @@ export class Series<T extends TelemValue = TelemValue> {
498
505
  return new Series({
499
506
  data: data.buffer,
500
507
  dataType: target,
501
- timeRange: this._timeRange,
508
+ timeRange: this.timeRange,
502
509
  sampleOffset,
503
510
  glBufferUsage: this.gl.bufferUsage,
504
511
  alignment: this.alignment,
@@ -696,28 +703,8 @@ export class Series<T extends TelemValue = TelemValue> {
696
703
  as(jsType: "bigint"): Series<bigint>;
697
704
 
698
705
  as<T extends TelemValue>(jsType: "string" | "number" | "bigint"): Series<T> {
699
- if (jsType === "string") {
700
- if (!this.dataType.equals(DataType.STRING))
701
- throw new Error(
702
- `cannot convert series of type ${this.dataType.toString()} to string`,
703
- );
704
- return this as unknown as Series<T>;
705
- }
706
- if (jsType === "number") {
707
- if (!this.dataType.isNumeric)
708
- throw new Error(
709
- `cannot convert series of type ${this.dataType.toString()} to number`,
710
- );
711
- return this as unknown as Series<T>;
712
- }
713
- if (jsType === "bigint") {
714
- if (!this.dataType.equals(DataType.INT64))
715
- throw new Error(
716
- `cannot convert series of type ${this.dataType.toString()} to bigint`,
717
- );
718
- return this as unknown as Series<T>;
719
- }
720
- throw new Error(`cannot convert series to ${jsType as string}`);
706
+ checkAsType(jsType, this.dataType);
707
+ return this as unknown as Series<T>;
721
708
  }
722
709
 
723
710
  get digest(): SeriesDigest {
@@ -729,7 +716,7 @@ export class Series<T extends TelemValue = TelemValue> {
729
716
  lower: alignmentDigest(this.alignmentBounds.lower),
730
717
  upper: alignmentDigest(this.alignmentBounds.upper),
731
718
  },
732
- timeRange: this._timeRange?.toString(),
719
+ timeRange: this.timeRange?.toString(),
733
720
  length: this.length,
734
721
  capacity: this.capacity,
735
722
  };
@@ -798,7 +785,7 @@ export class Series<T extends TelemValue = TelemValue> {
798
785
  return new Series({
799
786
  data,
800
787
  dataType: this.dataType,
801
- timeRange: this._timeRange,
788
+ timeRange: this.timeRange,
802
789
  sampleOffset: this.sampleOffset,
803
790
  glBufferUsage: this.gl.bufferUsage,
804
791
  alignment: this.alignment + BigInt(start),
@@ -813,7 +800,7 @@ export class Series<T extends TelemValue = TelemValue> {
813
800
  return new Series({
814
801
  data,
815
802
  dataType: this.dataType,
816
- timeRange: this._timeRange,
803
+ timeRange: this.timeRange,
817
804
  sampleOffset: this.sampleOffset,
818
805
  glBufferUsage: this.gl.bufferUsage,
819
806
  alignment: this.alignment + BigInt(start),
@@ -830,6 +817,24 @@ export class Series<T extends TelemValue = TelemValue> {
830
817
  alignment,
831
818
  });
832
819
  }
820
+
821
+ toString(): string {
822
+ let data = `${this.dataType.toString()} ${this.length} [`;
823
+ if (this.length <= 10) data += Array.from(this).map((v) => v.toString());
824
+ else {
825
+ for (let i = 0; i < 5; i++) {
826
+ data += `${this.at(i)?.toString()}`;
827
+ if (i < 4) data += ",";
828
+ }
829
+ data += "...";
830
+ for (let i = -5; i < 0; i++) {
831
+ data += this.at(i)?.toString();
832
+ if (i < -1) data += ",";
833
+ }
834
+ }
835
+ data += "]";
836
+ return data;
837
+ }
833
838
  }
834
839
 
835
840
  class SubIterator<T> implements Iterator<T>, Iterable<T> {
@@ -887,6 +892,7 @@ class StringSeriesIterator implements Iterator<string> {
887
892
 
888
893
  class JSONSeriesIterator implements Iterator<unknown> {
889
894
  private readonly wrapped: Iterator<string>;
895
+ private static SCHEMA = z.record(z.string(), z.unknown());
890
896
 
891
897
  constructor(wrapped: Iterator<string>) {
892
898
  this.wrapped = wrapped;
@@ -897,7 +903,7 @@ class JSONSeriesIterator implements Iterator<unknown> {
897
903
  if (next.done === true) return { done: true, value: undefined };
898
904
  return {
899
905
  done: false,
900
- value: binary.JSON_CODEC.decodeString(next.value),
906
+ value: binary.JSON_CODEC.decodeString(next.value, JSONSeriesIterator.SCHEMA),
901
907
  };
902
908
  }
903
909
 
@@ -934,7 +940,7 @@ class FixedSeriesIterator implements Iterator<math.Numeric> {
934
940
  export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<T> {
935
941
  readonly series: Array<Series<T>>;
936
942
 
937
- constructor(series: Array<Series<T>>) {
943
+ constructor(series: Array<Series<T>> = []) {
938
944
  if (series.length !== 0) {
939
945
  const type = series[0].dataType;
940
946
  for (let i = 1; i < series.length; i++)
@@ -950,11 +956,8 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
950
956
 
951
957
  as(jsType: "bigint"): MultiSeries<bigint>;
952
958
 
953
- as<T extends TelemValue>(dataType: CrudeDataType): MultiSeries<T> {
954
- if (!new DataType(dataType).equals(this.dataType))
955
- throw new Error(
956
- `cannot convert series of type ${this.dataType.toString()} to ${dataType.toString()}`,
957
- );
959
+ as<T extends TelemValue>(jsType: "string" | "number" | "bigint"): MultiSeries<T> {
960
+ checkAsType(jsType, this.dataType);
958
961
  return this as unknown as MultiSeries<T>;
959
962
  }
960
963
 
@@ -984,8 +987,12 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
984
987
  );
985
988
  }
986
989
 
987
- push(series: Series<T>): void {
988
- this.series.push(series);
990
+ push(series: Series<T>): void;
991
+ push(series: MultiSeries<T>): void;
992
+
993
+ push(series: Series<T> | MultiSeries<T>): void {
994
+ if ("isSynnaxSeries" in series && series.isSynnaxSeries) this.series.push(series);
995
+ else this.series.push(...(series as MultiSeries<T>).series);
989
996
  }
990
997
 
991
998
  get length(): number {
@@ -1067,6 +1074,14 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
1067
1074
  return new MultiSubIterator(this, startIdx, startIdx + span);
1068
1075
  }
1069
1076
 
1077
+ updateGLBuffer(gl: GLBufferController): void {
1078
+ this.series.forEach((s) => s.updateGLBuffer(gl));
1079
+ }
1080
+
1081
+ get bounds(): bounds.Bounds {
1082
+ return bounds.max(this.series.map((s) => s.bounds));
1083
+ }
1084
+
1070
1085
  get byteLength(): Size {
1071
1086
  return new Size(this.series.reduce((a, b) => a + b.byteLength.valueOf(), 0));
1072
1087
  }
@@ -1086,6 +1101,14 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
1086
1101
  return bounds.traverse(b, start, dist);
1087
1102
  }
1088
1103
 
1104
+ acquire(): void {
1105
+ this.series.forEach((s) => s.acquire());
1106
+ }
1107
+
1108
+ release(): void {
1109
+ this.series.forEach((s) => s.release());
1110
+ }
1111
+
1089
1112
  distance(start: bigint, end: bigint): bigint {
1090
1113
  const b = this.series.map((s) => s.alignmentBounds);
1091
1114
  return bounds.distance(b, start, end);
@@ -19,6 +19,7 @@ import {
19
19
  TimeRange,
20
20
  TimeSpan,
21
21
  TimeStamp,
22
+ type TimeStampStringFormat,
22
23
  } from "@/telem";
23
24
 
24
25
  describe("TimeStamp", () => {
@@ -177,19 +178,159 @@ describe("TimeStamp", () => {
177
178
  expect(ts.sub(TimeSpan.microseconds()).equals(new TimeStamp(0))).toBeTruthy();
178
179
  });
179
180
 
180
- test("stringification", () => {
181
+ describe("fString", () => {
181
182
  const ts = new TimeStamp([2022, 12, 15], "UTC")
182
183
  .add(TimeSpan.hours(12))
183
184
  .add(TimeSpan.minutes(20))
184
185
  .add(TimeSpan.milliseconds(12));
185
- expect(ts.fString("ISO", "UTC")).toEqual("2022-12-15T12:20:00.012Z");
186
- expect(ts.fString("time", "UTC")).toEqual("12:20:00");
187
- expect(ts.fString("date", "UTC")).toEqual("Dec 15");
188
- if (!TimeStamp.utcOffset.equals(0)) {
189
- expect(ts.fString("ISO", "local")).not.toEqual("2022-12-15T12:20:00.012Z");
190
- expect(ts.fString("time", "local")).not.toEqual("12:20:00");
191
- }
186
+
187
+ const FORMAT_TESTS: [TimeStampStringFormat, string][] = [
188
+ ["ISO", "2022-12-15T12:20:00.012Z"],
189
+ ["ISODate", "2022-12-15"],
190
+ ["ISOTime", "12:20:00.012"],
191
+ ["time", "12:20:00"],
192
+ ["preciseTime", "12:20:00.012"],
193
+ ["date", "Dec 15"],
194
+ ["preciseDate", "Dec 15 12:20:00.012"],
195
+ ["dateTime", "Dec 15 12:20:00"],
196
+ ];
197
+
198
+ FORMAT_TESTS.forEach(([format, expected]) => {
199
+ test(`should format timestamp as ${format}`, () => {
200
+ expect(ts.fString(format, "UTC")).toEqual(expected);
201
+ });
202
+ });
192
203
  });
204
+
205
+ describe("unit getters", () => {
206
+ test("hour", () => {
207
+ expect(TimeStamp.hours(1).add(TimeSpan.minutes(30)).hour).toEqual(1);
208
+ });
209
+ test("hours", () => {
210
+ expect(TimeStamp.hours(1).add(TimeSpan.minutes(30)).hours).toEqual(1.5);
211
+ });
212
+ test("minute", () => {
213
+ expect(TimeStamp.minutes(1).add(TimeStamp.seconds(20)).minute).toEqual(1);
214
+ });
215
+ test("minutes", () => {
216
+ expect(TimeStamp.minutes(1).add(TimeStamp.seconds(30)).minutes).toEqual(1.5);
217
+ });
218
+ test("second", () => {
219
+ expect(TimeStamp.seconds(1).add(TimeStamp.milliseconds(20)).second).toEqual(1);
220
+ });
221
+ test("seconds", () => {
222
+ expect(TimeStamp.seconds(1).add(TimeStamp.milliseconds(500)).seconds).toEqual(
223
+ 1.5,
224
+ );
225
+ });
226
+ test("millisecond", () => {
227
+ expect(
228
+ TimeStamp.milliseconds(1).add(TimeStamp.microseconds(20)).millisecond,
229
+ ).toEqual(1);
230
+ });
231
+ test("milliseconds", () => {
232
+ expect(
233
+ TimeStamp.milliseconds(1).add(TimeStamp.microseconds(500)).milliseconds,
234
+ ).toEqual(1.5);
235
+ });
236
+ test("microseconds", () => {
237
+ expect(
238
+ TimeStamp.microseconds(500).add(TimeSpan.nanoseconds(20)).microseconds,
239
+ ).toEqual(500.02);
240
+ });
241
+ test("nanoseconds", () => {
242
+ expect(
243
+ TimeStamp.microseconds(1).add(TimeSpan.nanoseconds(30)).nanoseconds,
244
+ ).toEqual(1030);
245
+ });
246
+ test("year", () => {
247
+ expect(new TimeStamp([2022, 12, 15]).year).toEqual(2022);
248
+ });
249
+ test("month", () => {
250
+ expect(new TimeStamp([2022, 12, 15]).month).toEqual(11);
251
+ });
252
+ test("day", () => {
253
+ expect(new TimeStamp([2022, 12, 15]).day).toEqual(15);
254
+ });
255
+ });
256
+
257
+ describe("unit setters", () => {
258
+ test("setYear", () => {
259
+ const ts = new TimeStamp([2022, 12, 15]);
260
+ const updated = ts.setYear(2023);
261
+ expect(updated.year).toEqual(2023);
262
+ expect(updated.month).toEqual(ts.month); // Other components should remain unchanged
263
+ expect(updated.day).toEqual(ts.day);
264
+ });
265
+
266
+ test("setMonth", () => {
267
+ const ts = new TimeStamp([2022, 12, 15]);
268
+ const updated = ts.setMonth(5); // June (0-indexed)
269
+ expect(updated.month).toEqual(5);
270
+ expect(updated.year).toEqual(ts.year); // Other components should remain unchanged
271
+ expect(updated.day).toEqual(ts.day);
272
+ });
273
+
274
+ test("setDay", () => {
275
+ const ts = new TimeStamp([2022, 12, 15]);
276
+ const updated = ts.setDay(20);
277
+ expect(updated.day).toEqual(20);
278
+ expect(updated.year).toEqual(ts.year);
279
+ expect(updated.month).toEqual(ts.month);
280
+ });
281
+
282
+ test("setHour", () => {
283
+ const ts = new TimeStamp([2022, 12, 15]).add(TimeSpan.hours(10));
284
+ const updated = ts.setHour(15);
285
+ expect(updated.hour).toEqual(15);
286
+ expect(updated.year).toEqual(ts.year);
287
+ expect(updated.month).toEqual(ts.month);
288
+ expect(updated.day).toEqual(ts.day);
289
+ });
290
+
291
+ test("setMinute", () => {
292
+ const ts = new TimeStamp([2022, 12, 15])
293
+ .add(TimeSpan.hours(10))
294
+ .add(TimeSpan.minutes(30));
295
+ const updated = ts.setMinute(45);
296
+ expect(updated.minute).toEqual(45);
297
+ expect(updated.hour).toEqual(ts.hour);
298
+ expect(updated.year).toEqual(ts.year);
299
+ expect(updated.month).toEqual(ts.month);
300
+ expect(updated.day).toEqual(ts.day);
301
+ });
302
+
303
+ test("setSecond", () => {
304
+ const ts = new TimeStamp([2022, 12, 15])
305
+ .add(TimeSpan.hours(10))
306
+ .add(TimeSpan.minutes(30))
307
+ .add(TimeSpan.seconds(20));
308
+ const updated = ts.setSecond(45);
309
+ expect(updated.second).toEqual(45);
310
+ expect(updated.minute).toEqual(ts.minute); // Other components should remain unchanged
311
+ expect(updated.hour).toEqual(ts.hour);
312
+ expect(updated.year).toEqual(ts.year);
313
+ expect(updated.month).toEqual(ts.month);
314
+ expect(updated.day).toEqual(ts.day);
315
+ });
316
+
317
+ test("setMillisecond", () => {
318
+ const ts = new TimeStamp([2022, 12, 15])
319
+ .add(TimeSpan.hours(10))
320
+ .add(TimeSpan.minutes(30))
321
+ .add(TimeSpan.seconds(20))
322
+ .add(TimeSpan.milliseconds(100));
323
+ const updated = ts.setMillisecond(500);
324
+ expect(updated.millisecond).toEqual(500);
325
+ expect(updated.second).toEqual(ts.second); // Other components should remain unchanged
326
+ expect(updated.minute).toEqual(ts.minute);
327
+ expect(updated.hour).toEqual(ts.hour);
328
+ expect(updated.year).toEqual(ts.year);
329
+ expect(updated.month).toEqual(ts.month);
330
+ expect(updated.day).toEqual(ts.day);
331
+ });
332
+ });
333
+
193
334
  describe("remainder", () => {
194
335
  test("day", () => {
195
336
  const expectedRemainder = TimeStamp.hours(12)
@@ -463,8 +604,8 @@ describe("TimeRange", () => {
463
604
  TimeSpan.seconds(1),
464
605
  TimeSpan.seconds(4).add(TimeSpan.milliseconds(500)),
465
606
  );
466
- expect(tr.roughlyEquals(one, TimeSpan.seconds(1))).toBeTruthy();
467
- expect(tr.roughlyEquals(one, TimeSpan.seconds(0))).toBeFalsy();
607
+ expect(tr.equals(one, TimeSpan.seconds(1))).toBeTruthy();
608
+ expect(tr.equals(one, TimeSpan.seconds(0))).toBeFalsy();
468
609
  });
469
610
  });
470
611