@synnaxlabs/x 0.47.0 → 0.49.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.
- package/.turbo/turbo-build.log +7 -105
- package/dist/src/deep/join.d.ts.map +1 -0
- package/dist/src/deep/path.d.ts +1 -1
- package/dist/src/deep/path.d.ts.map +1 -1
- package/dist/src/destructor/destructor.d.ts +7 -0
- package/dist/src/destructor/destructor.d.ts.map +1 -0
- package/dist/src/destructor/index.d.ts +2 -0
- package/dist/src/destructor/index.d.ts.map +1 -0
- package/dist/src/index.d.ts +5 -10
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/math/constants.d.ts +1 -0
- package/dist/src/math/constants.d.ts.map +1 -1
- package/dist/src/migrate/migrate.d.ts +4 -4
- package/dist/src/migrate/migrate.d.ts.map +1 -1
- package/dist/src/narrow/index.d.ts +2 -0
- package/dist/src/narrow/index.d.ts.map +1 -0
- package/dist/src/narrow/narrow.d.ts +4 -0
- package/dist/src/narrow/narrow.d.ts.map +1 -0
- package/dist/src/narrow/narrow.spec.d.ts +2 -0
- package/dist/src/narrow/narrow.spec.d.ts.map +1 -0
- package/dist/src/numeric/numeric.d.ts +0 -1
- package/dist/src/numeric/numeric.d.ts.map +1 -1
- package/dist/src/observe/observe.d.ts +4 -4
- package/dist/src/observe/observe.d.ts.map +1 -1
- package/dist/src/optional/index.d.ts +2 -0
- package/dist/src/optional/index.d.ts.map +1 -0
- package/dist/src/optional/optional.d.ts.map +1 -0
- package/dist/src/scheduler/index.d.ts +2 -0
- package/dist/src/scheduler/index.d.ts.map +1 -0
- package/dist/src/{flush.d.ts → scheduler/scheduler.d.ts} +1 -1
- package/dist/src/scheduler/scheduler.d.ts.map +1 -0
- package/dist/src/scheduler/scheduler.spec.d.ts +2 -0
- package/dist/src/scheduler/scheduler.spec.d.ts.map +1 -0
- package/dist/src/shallow/copy.d.ts +2 -0
- package/dist/src/shallow/copy.d.ts.map +1 -0
- package/dist/src/shallow/copy.spec.d.ts +2 -0
- package/dist/src/shallow/copy.spec.d.ts.map +1 -0
- package/dist/src/shallow/index.d.ts +2 -0
- package/dist/src/shallow/index.d.ts.map +1 -0
- package/dist/src/spatial/base.d.ts +5 -38
- package/dist/src/spatial/base.d.ts.map +1 -1
- package/dist/src/spatial/direction/direction.d.ts +2 -1
- package/dist/src/spatial/direction/direction.d.ts.map +1 -1
- package/dist/src/spatial/external.d.ts +2 -1
- package/dist/src/spatial/external.d.ts.map +1 -1
- package/dist/src/spatial/location/location.d.ts +2 -2
- package/dist/src/spatial/location/location.d.ts.map +1 -1
- package/dist/src/spatial/sticky/index.d.ts +2 -0
- package/dist/src/spatial/sticky/index.d.ts.map +1 -0
- package/dist/src/spatial/sticky/sticky.d.ts +74 -0
- package/dist/src/spatial/sticky/sticky.d.ts.map +1 -0
- package/dist/src/spatial/sticky/sticky.spec.d.ts +2 -0
- package/dist/src/spatial/sticky/sticky.spec.d.ts.map +1 -0
- package/dist/src/spatial/xy/xy.d.ts +10 -2
- package/dist/src/spatial/xy/xy.d.ts.map +1 -1
- package/dist/src/status/status.d.ts +2 -2
- package/dist/src/status/status.d.ts.map +1 -1
- package/dist/src/telem/series.d.ts +4 -4
- package/dist/src/telem/series.d.ts.map +1 -1
- package/dist/src/telem/telem.d.ts +14 -1
- package/dist/src/telem/telem.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +2 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/zod/external.d.ts +1 -0
- package/dist/src/zod/external.d.ts.map +1 -1
- package/dist/src/zod/schemas.d.ts +3 -0
- package/dist/src/zod/schemas.d.ts.map +1 -0
- package/dist/src/zod/schemas.spec.d.ts +2 -0
- package/dist/src/zod/schemas.spec.d.ts.map +1 -0
- package/dist/x.cjs +12 -0
- package/dist/x.js +5521 -0
- package/package.json +12 -150
- package/src/binary/codec.ts +2 -2
- package/src/deep/merge.ts +3 -3
- package/src/deep/path.ts +1 -1
- package/src/{destructor.ts → destructor/destructor.ts} +1 -1
- package/src/{invert.ts → destructor/index.ts} +1 -1
- package/src/index.ts +5 -10
- package/src/math/constants.ts +1 -0
- package/src/migrate/migrate.spec.ts +238 -0
- package/src/migrate/migrate.ts +67 -7
- package/src/{mock → narrow}/index.ts +1 -1
- package/src/narrow/narrow.spec.ts +70 -0
- package/src/{identity.ts → narrow/narrow.ts} +6 -0
- package/src/numeric/numeric.ts +0 -5
- package/src/observe/observe.ts +4 -4
- package/src/{replace.ts → optional/index.ts} +1 -1
- package/src/scheduler/index.ts +10 -0
- package/src/scheduler/scheduler.spec.ts +82 -0
- package/src/shallow/copy.spec.ts +141 -0
- package/src/{shallowCopy.ts → shallow/copy.ts} +1 -1
- package/src/shallow/index.ts +10 -0
- package/src/spatial/base.ts +6 -15
- package/src/spatial/direction/direction.ts +2 -0
- package/src/spatial/external.ts +2 -1
- package/src/spatial/location/location.spec.ts +16 -0
- package/src/spatial/location/location.ts +7 -7
- package/src/spatial/sticky/index.ts +10 -0
- package/src/spatial/sticky/sticky.spec.ts +584 -0
- package/src/spatial/sticky/sticky.ts +98 -0
- package/src/spatial/xy/xy.spec.ts +55 -0
- package/src/spatial/xy/xy.ts +27 -2
- package/src/status/status.ts +5 -5
- package/src/telem/series.ts +5 -6
- package/src/telem/telem.spec.ts +87 -28
- package/src/telem/telem.ts +49 -9
- package/src/{clamp → types}/index.ts +1 -1
- package/src/zod/external.ts +1 -0
- package/src/zod/schemas.spec.ts +51 -0
- package/src/zod/schemas.ts +14 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vite.config.ts +1 -36
- package/dist/array.cjs +0 -1
- package/dist/array.js +0 -4
- package/dist/base-DRybODwJ.js +0 -42
- package/dist/base-KIBsp6TI.cjs +0 -1
- package/dist/binary.cjs +0 -1
- package/dist/binary.js +0 -4
- package/dist/bounds-4BWKPqaP.js +0 -183
- package/dist/bounds-C2TKFgVk.cjs +0 -1
- package/dist/bounds.cjs +0 -1
- package/dist/bounds.js +0 -4
- package/dist/box-BXWXSkKu.js +0 -203
- package/dist/box-rH3ggwXk.cjs +0 -1
- package/dist/box.cjs +0 -1
- package/dist/box.js +0 -4
- package/dist/caseconv.cjs +0 -1
- package/dist/caseconv.js +0 -4
- package/dist/change-C-YELKx6.cjs +0 -1
- package/dist/change-DLl6DccR.js +0 -12
- package/dist/change.cjs +0 -1
- package/dist/change.js +0 -4
- package/dist/compare-Bnx9CdjS.js +0 -119
- package/dist/compare-GPoFaKRW.cjs +0 -1
- package/dist/compare.cjs +0 -1
- package/dist/compare.js +0 -36
- package/dist/debounce.cjs +0 -1
- package/dist/debounce.js +0 -17
- package/dist/deep.cjs +0 -1
- package/dist/deep.js +0 -247
- package/dist/destructor.cjs +0 -1
- package/dist/destructor.js +0 -1
- package/dist/dimensions-Cg5Owbwn.cjs +0 -1
- package/dist/dimensions-DC0uLPwn.js +0 -43
- package/dist/dimensions.cjs +0 -1
- package/dist/dimensions.js +0 -4
- package/dist/direction-C_b4tfRN.js +0 -19
- package/dist/direction-DqQB9M37.cjs +0 -1
- package/dist/direction.cjs +0 -1
- package/dist/direction.js +0 -4
- package/dist/external-2YWy569j.js +0 -23
- package/dist/external-B6edOwoQ.cjs +0 -1
- package/dist/external-B80i4ymZ.js +0 -29
- package/dist/external-B9AAGv50.cjs +0 -1
- package/dist/external-BYuXBYJh.js +0 -40
- package/dist/external-BxmTQZ6m.cjs +0 -1
- package/dist/external-DLiGrXn7.cjs +0 -1
- package/dist/external-Du5qzfYv.js +0 -35
- package/dist/get-CtJEJIC_.js +0 -82
- package/dist/get-D2VRwUw4.cjs +0 -1
- package/dist/identity.cjs +0 -1
- package/dist/identity.js +0 -4
- package/dist/index-Bfvg0v-N.cjs +0 -3
- package/dist/index-Bv029kh3.js +0 -19
- package/dist/index-CqisIWWC.cjs +0 -1
- package/dist/index-CyNZHQFw.cjs +0 -1
- package/dist/index-qmkoZBNO.js +0 -57
- package/dist/index-yz34Wc2p.js +0 -92
- package/dist/index.cjs +0 -5
- package/dist/index.js +0 -985
- package/dist/kv.cjs +0 -1
- package/dist/kv.js +0 -4
- package/dist/link.cjs +0 -1
- package/dist/link.js +0 -10
- package/dist/location-0qDBiCqP.cjs +0 -1
- package/dist/location-BIzpxczO.js +0 -95
- package/dist/location.cjs +0 -1
- package/dist/location.js +0 -4
- package/dist/observe.cjs +0 -1
- package/dist/observe.js +0 -48
- package/dist/record-BwjIgrpU.cjs +0 -1
- package/dist/record-tSFQKmdG.js +0 -19
- package/dist/record.cjs +0 -1
- package/dist/record.js +0 -4
- package/dist/runtime.cjs +0 -1
- package/dist/runtime.js +0 -4
- package/dist/scale-BXy1w8R_.cjs +0 -1
- package/dist/scale-DJCMZbfU.js +0 -228
- package/dist/scale.cjs +0 -1
- package/dist/scale.js +0 -4
- package/dist/series-Bh0pHoUF.cjs +0 -6
- package/dist/series-Cf8rT2IX.js +0 -2810
- package/dist/spatial-DnsaOypA.js +0 -11
- package/dist/spatial-DrxzaD5U.cjs +0 -1
- package/dist/spatial.cjs +0 -1
- package/dist/spatial.js +0 -18
- package/dist/src/clamp/index.d.ts +0 -2
- package/dist/src/clamp/index.d.ts.map +0 -1
- package/dist/src/destructor.d.ts +0 -7
- package/dist/src/destructor.d.ts.map +0 -1
- package/dist/src/flush.d.ts.map +0 -1
- package/dist/src/identity.d.ts +0 -3
- package/dist/src/identity.d.ts.map +0 -1
- package/dist/src/invert.d.ts +0 -2
- package/dist/src/invert.d.ts.map +0 -1
- package/dist/src/join.d.ts.map +0 -1
- package/dist/src/mock/index.d.ts +0 -2
- package/dist/src/mock/index.d.ts.map +0 -1
- package/dist/src/optional.d.ts.map +0 -1
- package/dist/src/renderable.d.ts +0 -5
- package/dist/src/renderable.d.ts.map +0 -1
- package/dist/src/replace.d.ts +0 -2
- package/dist/src/replace.d.ts.map +0 -1
- package/dist/src/shallowCopy.d.ts +0 -2
- package/dist/src/shallowCopy.d.ts.map +0 -1
- package/dist/src/telem/generate.d.ts +0 -3
- package/dist/src/telem/generate.d.ts.map +0 -1
- package/dist/src/transform.d.ts +0 -6
- package/dist/src/transform.d.ts.map +0 -1
- package/dist/src/undefined.d.ts +0 -2
- package/dist/src/undefined.d.ts.map +0 -1
- package/dist/telem.cjs +0 -1
- package/dist/telem.js +0 -18
- package/dist/unique.cjs +0 -1
- package/dist/unique.js +0 -4
- package/dist/url.cjs +0 -1
- package/dist/url.js +0 -51
- package/dist/worker.cjs +0 -1
- package/dist/worker.js +0 -43
- package/dist/xy-C-MUIjVs.cjs +0 -1
- package/dist/xy-DnrCAZaw.js +0 -154
- package/dist/xy.cjs +0 -1
- package/dist/xy.js +0 -4
- package/dist/zod.cjs +0 -1
- package/dist/zod.js +0 -4
- package/src/renderable.ts +0 -20
- package/src/telem/generate.ts +0 -17
- package/src/transform.ts +0 -17
- package/src/undefined.ts +0 -14
- /package/dist/src/{join.d.ts → deep/join.d.ts} +0 -0
- /package/dist/src/{optional.d.ts → optional/optional.d.ts} +0 -0
- /package/src/{join.ts → deep/join.ts} +0 -0
- /package/src/{optional.ts → optional/optional.ts} +0 -0
- /package/src/{flush.ts → scheduler/scheduler.ts} +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
|
|
12
|
+
import { narrow } from "@/narrow";
|
|
13
|
+
|
|
14
|
+
describe("narrow", () => {
|
|
15
|
+
describe("isObject", () => {
|
|
16
|
+
it("should return true for plain objects", () => {
|
|
17
|
+
expect(narrow.isObject({})).toBe(true);
|
|
18
|
+
expect(narrow.isObject({ a: 1 })).toBe(true);
|
|
19
|
+
expect(narrow.isObject({ nested: { obj: true } })).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should return false for null", () => {
|
|
23
|
+
expect(narrow.isObject(null)).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should return false for undefined", () => {
|
|
27
|
+
expect(narrow.isObject(undefined)).toBe(false);
|
|
28
|
+
expect(narrow.isObject()).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should return false for arrays", () => {
|
|
32
|
+
expect(narrow.isObject([])).toBe(false);
|
|
33
|
+
expect(narrow.isObject([1, 2, 3])).toBe(false);
|
|
34
|
+
expect(narrow.isObject([{ a: 1 }])).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should return false for primitives", () => {
|
|
38
|
+
expect(narrow.isObject(0)).toBe(false);
|
|
39
|
+
expect(narrow.isObject(1)).toBe(false);
|
|
40
|
+
expect(narrow.isObject("")).toBe(false);
|
|
41
|
+
expect(narrow.isObject("string")).toBe(false);
|
|
42
|
+
expect(narrow.isObject(true)).toBe(false);
|
|
43
|
+
expect(narrow.isObject(false)).toBe(false);
|
|
44
|
+
expect(narrow.isObject(Symbol("test"))).toBe(false);
|
|
45
|
+
expect(narrow.isObject(42n)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should return true for class instances", () => {
|
|
49
|
+
class TestClass {}
|
|
50
|
+
expect(narrow.isObject(new TestClass())).toBe(true);
|
|
51
|
+
expect(narrow.isObject(new Date())).toBe(true);
|
|
52
|
+
expect(narrow.isObject(new Map())).toBe(true);
|
|
53
|
+
expect(narrow.isObject(new Set())).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should return true for Object.create(null)", () => {
|
|
57
|
+
expect(narrow.isObject(Object.create(null))).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should return false for functions", () => {
|
|
61
|
+
expect(narrow.isObject(() => {})).toBe(false);
|
|
62
|
+
expect(narrow.isObject(() => {})).toBe(false);
|
|
63
|
+
expect(narrow.isObject(async () => {})).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should return true for regex", () => {
|
|
67
|
+
expect(narrow.isObject(/test/)).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
import { type record } from "@/record";
|
|
11
11
|
|
|
12
|
+
export type IsUndefined<T> = [T] extends [undefined] // T can be assigned to undefined
|
|
13
|
+
? [undefined] extends [T] // undefined can be assigned to T
|
|
14
|
+
? true // both directions → exactly undefined
|
|
15
|
+
: false
|
|
16
|
+
: false;
|
|
17
|
+
|
|
12
18
|
export const isObject = <T extends record.Unknown = record.Unknown>(
|
|
13
19
|
item?: unknown,
|
|
14
20
|
): item is T => item != null && typeof item === "object" && !Array.isArray(item);
|
package/src/numeric/numeric.ts
CHANGED
package/src/observe/observe.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
import { type
|
|
10
|
+
import { type destructor } from "@/destructor";
|
|
11
11
|
|
|
12
12
|
/** Handler is called when the value of an Observable changes. */
|
|
13
13
|
export type Handler<T> = (value: T) => void;
|
|
@@ -22,7 +22,7 @@ export interface Observable<T> {
|
|
|
22
22
|
* @param handler The handler to bind to the Observable.
|
|
23
23
|
* @returns A function that can be called to unbind the handler from the Observable.
|
|
24
24
|
*/
|
|
25
|
-
onChange: (handler: Handler<T>) => Destructor;
|
|
25
|
+
onChange: (handler: Handler<T>) => destructor.Destructor;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/** An Observable that can be closed using an async function. */
|
|
@@ -52,7 +52,7 @@ export class Observer<I, O = I> implements ObservableAsyncCloseable<O> {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/** Implements the observable interface. */
|
|
55
|
-
onChange(handler: Handler<O>): Destructor {
|
|
55
|
+
onChange(handler: Handler<O>): destructor.Destructor {
|
|
56
56
|
this.handlers.set(handler, null);
|
|
57
57
|
return () => this.handlers.delete(handler);
|
|
58
58
|
}
|
|
@@ -84,7 +84,7 @@ export class BaseObserver<V> implements Observable<V> {
|
|
|
84
84
|
this.handlers = handlers ?? new Map();
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
onChange(handler: Handler<V>): Destructor {
|
|
87
|
+
onChange(handler: Handler<V>): destructor.Destructor {
|
|
88
88
|
this.handlers.set(handler, null);
|
|
89
89
|
return () => this.handlers.delete(handler);
|
|
90
90
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
export * as scheduler from "@/scheduler/scheduler";
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
|
|
12
|
+
import { scheduler } from "@/scheduler";
|
|
13
|
+
|
|
14
|
+
describe("scheduler", () => {
|
|
15
|
+
describe("flushMicrotasks", () => {
|
|
16
|
+
it("should return a resolved promise", async () => {
|
|
17
|
+
const result = scheduler.flushMicrotasks();
|
|
18
|
+
expect(result).toBeInstanceOf(Promise);
|
|
19
|
+
await expect(result).resolves.toBeUndefined();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should flush microtasks before continuing", async () => {
|
|
23
|
+
const order: number[] = [];
|
|
24
|
+
void Promise.resolve().then(() => order.push(1));
|
|
25
|
+
void Promise.resolve().then(() => order.push(2));
|
|
26
|
+
await scheduler.flushMicrotasks();
|
|
27
|
+
expect(order).toEqual([1, 2]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should resolve immediately without waiting for macrotasks", async () => {
|
|
31
|
+
const order: number[] = [];
|
|
32
|
+
setTimeout(() => order.push(1), 0);
|
|
33
|
+
await scheduler.flushMicrotasks();
|
|
34
|
+
expect(order).toEqual([]);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("flushTaskQueue", () => {
|
|
39
|
+
it("should return a promise", async () => {
|
|
40
|
+
const result = scheduler.flushTaskQueue();
|
|
41
|
+
expect(result).toBeInstanceOf(Promise);
|
|
42
|
+
await expect(result).resolves.toBeUndefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should flush macrotasks from setTimeout", async () => {
|
|
46
|
+
const order: number[] = [];
|
|
47
|
+
setTimeout(() => order.push(1), 0);
|
|
48
|
+
setTimeout(() => order.push(2), 0);
|
|
49
|
+
await scheduler.flushTaskQueue();
|
|
50
|
+
expect(order).toEqual([1, 2]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should execute after microtasks", async () => {
|
|
54
|
+
const order: string[] = [];
|
|
55
|
+
void Promise.resolve().then(() => order.push("micro"));
|
|
56
|
+
setTimeout(() => order.push("macro"), 0);
|
|
57
|
+
await scheduler.flushTaskQueue();
|
|
58
|
+
expect(order).toEqual(["micro", "macro"]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should handle nested flushes", async () => {
|
|
62
|
+
const order: number[] = [];
|
|
63
|
+
setTimeout(() => order.push(1), 0);
|
|
64
|
+
await scheduler.flushTaskQueue();
|
|
65
|
+
setTimeout(() => order.push(2), 0);
|
|
66
|
+
await scheduler.flushTaskQueue();
|
|
67
|
+
expect(order).toEqual([1, 2]);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe("flush order", () => {
|
|
72
|
+
it("should flush microtasks before macrotasks", async () => {
|
|
73
|
+
const order: string[] = [];
|
|
74
|
+
setTimeout(() => order.push("macro"), 0);
|
|
75
|
+
void Promise.resolve().then(() => order.push("micro"));
|
|
76
|
+
await scheduler.flushMicrotasks();
|
|
77
|
+
expect(order).toEqual(["micro"]);
|
|
78
|
+
await scheduler.flushTaskQueue();
|
|
79
|
+
expect(order).toEqual(["micro", "macro"]);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
|
|
12
|
+
import { shallow } from "@/shallow";
|
|
13
|
+
|
|
14
|
+
describe("shallow", () => {
|
|
15
|
+
describe("copy", () => {
|
|
16
|
+
it("should shallow copy plain objects", () => {
|
|
17
|
+
const obj = { a: 1, b: 2 };
|
|
18
|
+
const copied = shallow.copy(obj);
|
|
19
|
+
expect(copied).toEqual(obj);
|
|
20
|
+
expect(copied).not.toBe(obj);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should shallow copy arrays", () => {
|
|
24
|
+
const arr = [1, 2, 3];
|
|
25
|
+
const copied = shallow.copy(arr);
|
|
26
|
+
expect(copied).toEqual(arr);
|
|
27
|
+
expect(copied).not.toBe(arr);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should not deep copy nested objects", () => {
|
|
31
|
+
const obj = { a: 1, nested: { b: 2 } };
|
|
32
|
+
const copied = shallow.copy(obj);
|
|
33
|
+
expect(copied.nested).toBe(obj.nested);
|
|
34
|
+
copied.nested.b = 999;
|
|
35
|
+
expect(obj.nested.b).toBe(999);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should not deep copy nested arrays", () => {
|
|
39
|
+
const arr = [1, [2, 3]];
|
|
40
|
+
const copied = shallow.copy(arr);
|
|
41
|
+
expect(copied[1]).toBe(arr[1]);
|
|
42
|
+
(copied[1] as number[])[0] = 999;
|
|
43
|
+
expect((arr[1] as number[])[0]).toBe(999);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should return primitives as-is", () => {
|
|
47
|
+
expect(shallow.copy(42)).toBe(42);
|
|
48
|
+
expect(shallow.copy("string")).toBe("string");
|
|
49
|
+
expect(shallow.copy(true)).toBe(true);
|
|
50
|
+
expect(shallow.copy(false)).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should return null as-is", () => {
|
|
54
|
+
expect(shallow.copy(null)).toBe(null);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should return undefined as-is", () => {
|
|
58
|
+
expect(shallow.copy(undefined)).toBe(undefined);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should copy arrays with objects", () => {
|
|
62
|
+
const arr = [{ a: 1 }, { b: 2 }];
|
|
63
|
+
const copied = shallow.copy(arr);
|
|
64
|
+
expect(copied).not.toBe(arr);
|
|
65
|
+
expect(copied[0]).toBe(arr[0]);
|
|
66
|
+
expect(copied[1]).toBe(arr[1]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should copy objects with various types", () => {
|
|
70
|
+
const obj = {
|
|
71
|
+
num: 42,
|
|
72
|
+
str: "test",
|
|
73
|
+
bool: true,
|
|
74
|
+
arr: [1, 2],
|
|
75
|
+
nested: { x: 1 },
|
|
76
|
+
};
|
|
77
|
+
const copied = shallow.copy(obj);
|
|
78
|
+
expect(copied).toEqual(obj);
|
|
79
|
+
expect(copied).not.toBe(obj);
|
|
80
|
+
expect(copied.arr).toBe(obj.arr);
|
|
81
|
+
expect(copied.nested).toBe(obj.nested);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should copy empty objects", () => {
|
|
85
|
+
const obj = {};
|
|
86
|
+
const copied = shallow.copy(obj);
|
|
87
|
+
expect(copied).toEqual({});
|
|
88
|
+
expect(copied).not.toBe(obj);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should copy empty arrays", () => {
|
|
92
|
+
const arr: unknown[] = [];
|
|
93
|
+
const copied = shallow.copy(arr);
|
|
94
|
+
expect(copied).toEqual([]);
|
|
95
|
+
expect(copied).not.toBe(arr);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should handle class instances", () => {
|
|
99
|
+
class TestClass {
|
|
100
|
+
value = 42;
|
|
101
|
+
}
|
|
102
|
+
const instance = new TestClass();
|
|
103
|
+
const copied = shallow.copy(instance);
|
|
104
|
+
expect(copied).not.toBe(instance);
|
|
105
|
+
expect(copied.value).toBe(42);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should spread Date objects into plain objects", () => {
|
|
109
|
+
const date = new Date("2025-01-01");
|
|
110
|
+
const copied = shallow.copy(date);
|
|
111
|
+
expect(copied).not.toBe(date);
|
|
112
|
+
expect(copied).toEqual({});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should handle objects with symbol keys", () => {
|
|
116
|
+
const sym = Symbol("test");
|
|
117
|
+
const obj = { [sym]: "value", regular: 1 };
|
|
118
|
+
const copied = shallow.copy(obj);
|
|
119
|
+
expect(copied[sym]).toBe("value");
|
|
120
|
+
expect(copied.regular).toBe(1);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should lose prototype when spreading objects", () => {
|
|
124
|
+
class Custom {
|
|
125
|
+
x = 1;
|
|
126
|
+
}
|
|
127
|
+
const obj = new Custom();
|
|
128
|
+
const copied = shallow.copy(obj);
|
|
129
|
+
expect(copied).not.toBeInstanceOf(Custom);
|
|
130
|
+
expect(copied.x).toBe(1);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("should fill holes in sparse arrays", () => {
|
|
134
|
+
const arr = [1, undefined, 3];
|
|
135
|
+
const copied = shallow.copy(arr);
|
|
136
|
+
expect(copied).not.toBe(arr);
|
|
137
|
+
expect(copied).toEqual([1, undefined, 3]);
|
|
138
|
+
expect(1 in copied).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
export const
|
|
10
|
+
export const copy = <T>(obj: T): T => {
|
|
11
11
|
if (Array.isArray(obj)) return [...obj] as T;
|
|
12
12
|
if (typeof obj === "object" && obj !== null) return { ...obj };
|
|
13
13
|
return obj;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
export * as shallow from "@/shallow/copy";
|
package/src/spatial/base.ts
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
12
|
export const numberCouple = z.tuple([z.number(), z.number()]);
|
|
13
|
-
export const bigNumberCouple = z.tuple([z.bigint(), z.bigint()]);
|
|
14
13
|
export type NumberCouple<T extends number | bigint = number> = [T, T];
|
|
15
14
|
|
|
16
15
|
// Dimensions
|
|
@@ -21,13 +20,9 @@ export const signedDimensions = z.object({
|
|
|
21
20
|
signedWidth: z.number(),
|
|
22
21
|
signedHeight: z.number(),
|
|
23
22
|
});
|
|
24
|
-
export
|
|
25
|
-
export const dimension = z.enum(DIMENSIONS);
|
|
26
|
-
export type Dimension = (typeof DIMENSIONS)[number];
|
|
23
|
+
export type Dimension = "width" | "height";
|
|
27
24
|
export const ALIGNMENTS = ["start", "center", "end"] as const;
|
|
28
|
-
export
|
|
29
|
-
export const signedDimension = z.enum(SIGNED_DIMENSIONS);
|
|
30
|
-
export type SignedDimension = (typeof SIGNED_DIMENSIONS)[number];
|
|
25
|
+
export type SignedDimension = "signedWidth" | "signedHeight";
|
|
31
26
|
|
|
32
27
|
// XY
|
|
33
28
|
|
|
@@ -56,7 +51,7 @@ export type YLocation = (typeof Y_LOCATIONS)[number];
|
|
|
56
51
|
export const CENTER_LOCATIONS = ["center"] as const;
|
|
57
52
|
export const centerLocation = z.enum(CENTER_LOCATIONS);
|
|
58
53
|
export type CenterLocation = (typeof CENTER_LOCATIONS)[number];
|
|
59
|
-
|
|
54
|
+
const LOCATIONS = [...OUTER_LOCATIONS, ...CENTER_LOCATIONS] as const;
|
|
60
55
|
export const location = z.enum(LOCATIONS);
|
|
61
56
|
export type Location = z.infer<typeof location>;
|
|
62
57
|
|
|
@@ -71,22 +66,18 @@ export type Order = (typeof ORDERS)[number];
|
|
|
71
66
|
// Bounds
|
|
72
67
|
|
|
73
68
|
export const bounds = z.object({ lower: z.number(), upper: z.number() });
|
|
74
|
-
export const bigBounds = z.object({ lower: z.bigint(), upper: z.bigint() });
|
|
75
69
|
export interface Bounds<T extends number | bigint = number> {
|
|
76
70
|
lower: T;
|
|
77
71
|
upper: T;
|
|
78
72
|
}
|
|
79
73
|
|
|
80
|
-
export const crudeBounds = z.union([bounds, numberCouple]);
|
|
81
|
-
export const bigCrudeBounds = z.union([bigBounds, numberCouple]);
|
|
82
74
|
export type CrudeBounds<T extends number | bigint = number> =
|
|
83
75
|
| Bounds<T>
|
|
84
76
|
| NumberCouple<T>;
|
|
85
77
|
export const crudeDirection = z.enum([...direction.options, ...location.options]);
|
|
86
|
-
export const crudeXDirection = z.enum(["x", "left", "right"]);
|
|
87
|
-
export const crudeYDirection = z.enum(["y", "top", "bottom"]);
|
|
88
78
|
export type CrudeDirection = z.infer<typeof crudeDirection>;
|
|
89
|
-
export type CrudeXDirection =
|
|
90
|
-
export type CrudeYDirection =
|
|
79
|
+
export type CrudeXDirection = "x" | "left" | "right";
|
|
80
|
+
export type CrudeYDirection = "y" | "top" | "bottom";
|
|
81
|
+
export type AngularDirection = "clockwise" | "counterclockwise";
|
|
91
82
|
export const crudeLocation = z.union([direction, location, z.instanceof(String)]);
|
|
92
83
|
export type CrudeLocation = z.infer<typeof crudeLocation>;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
+
type AngularDirection,
|
|
11
12
|
type CrudeDirection,
|
|
12
13
|
crudeDirection,
|
|
13
14
|
type CrudeXDirection,
|
|
@@ -29,6 +30,7 @@ export const crude = crudeDirection;
|
|
|
29
30
|
export type Crude = CrudeDirection;
|
|
30
31
|
export type CrudeX = CrudeXDirection;
|
|
31
32
|
export type CrudeY = CrudeYDirection;
|
|
33
|
+
export type Angular = AngularDirection;
|
|
32
34
|
|
|
33
35
|
export const construct = (c: Crude): Direction => {
|
|
34
36
|
if (DIRECTIONS.includes(c as Direction)) return c as Direction;
|
package/src/spatial/external.ts
CHANGED
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
10
|
export * from "@/spatial/bounds";
|
|
11
|
-
export
|
|
11
|
+
export * from "@/spatial/box";
|
|
12
12
|
export * from "@/spatial/dimensions";
|
|
13
13
|
export * from "@/spatial/direction";
|
|
14
14
|
export * from "@/spatial/location";
|
|
15
15
|
export * from "@/spatial/scale";
|
|
16
16
|
export * as spatial from "@/spatial/spatial";
|
|
17
|
+
export * from "@/spatial/sticky";
|
|
17
18
|
export * from "@/spatial/xy";
|
|
@@ -21,4 +21,20 @@ describe("Location", () => {
|
|
|
21
21
|
test(name, () => expect(location.construct(arg)).toEqual("left")),
|
|
22
22
|
);
|
|
23
23
|
});
|
|
24
|
+
|
|
25
|
+
describe("rotate", () => {
|
|
26
|
+
test("should rotate clockwise", () => {
|
|
27
|
+
expect(location.rotate("top", "clockwise")).toEqual("left");
|
|
28
|
+
expect(location.rotate("left", "clockwise")).toEqual("bottom");
|
|
29
|
+
expect(location.rotate("bottom", "clockwise")).toEqual("right");
|
|
30
|
+
expect(location.rotate("right", "clockwise")).toEqual("top");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("should rotate counterclockwise", () => {
|
|
34
|
+
expect(location.rotate("top", "counterclockwise")).toEqual("right");
|
|
35
|
+
expect(location.rotate("left", "counterclockwise")).toEqual("top");
|
|
36
|
+
expect(location.rotate("bottom", "counterclockwise")).toEqual("left");
|
|
37
|
+
expect(location.rotate("right", "counterclockwise")).toEqual("bottom");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
24
40
|
});
|
|
@@ -11,6 +11,7 @@ import { z } from "zod";
|
|
|
11
11
|
|
|
12
12
|
import { caseconv } from "@/caseconv";
|
|
13
13
|
import {
|
|
14
|
+
type AngularDirection,
|
|
14
15
|
CENTER_LOCATIONS,
|
|
15
16
|
type CenterLocation,
|
|
16
17
|
centerLocation,
|
|
@@ -58,12 +59,11 @@ const SWAPPED: Record<Location, Location> = {
|
|
|
58
59
|
center: "center",
|
|
59
60
|
};
|
|
60
61
|
|
|
61
|
-
const
|
|
62
|
-
top: "left",
|
|
63
|
-
right: "top",
|
|
64
|
-
bottom: "right",
|
|
65
|
-
left: "bottom",
|
|
66
|
-
center: "center",
|
|
62
|
+
const ROTATIONS: Record<Outer, Record<AngularDirection, Outer>> = {
|
|
63
|
+
top: { clockwise: "left", counterclockwise: "right" },
|
|
64
|
+
right: { clockwise: "top", counterclockwise: "bottom" },
|
|
65
|
+
bottom: { clockwise: "right", counterclockwise: "left" },
|
|
66
|
+
left: { clockwise: "bottom", counterclockwise: "top" },
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
export const crude = crudeLocation;
|
|
@@ -79,7 +79,7 @@ export const construct = (cl: Crude): Location => {
|
|
|
79
79
|
|
|
80
80
|
export const swap = (cl: Crude): Location => SWAPPED[construct(cl)];
|
|
81
81
|
|
|
82
|
-
export const
|
|
82
|
+
export const rotate = (loc: Outer, dir: AngularDirection): Outer => ROTATIONS[loc][dir];
|
|
83
83
|
|
|
84
84
|
export const direction = (cl: Crude): Direction => {
|
|
85
85
|
const l = construct(cl);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
export * as sticky from "@/spatial/sticky/sticky";
|