@synnaxlabs/x 0.45.0 → 0.45.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/dist/deep.cjs +1 -1
- package/dist/deep.js +211 -99
- package/dist/external-CtHGFcox.cjs +1 -0
- package/dist/{external-BM_NS5yM.js → external-tyaEMW4S.js} +1 -1
- package/dist/get-CXkBfLu1.js +82 -0
- package/dist/get-OP63N4c3.cjs +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/src/deep/copy.spec.d.ts +2 -0
- package/dist/src/deep/copy.spec.d.ts.map +1 -0
- package/dist/src/deep/external.d.ts +3 -1
- package/dist/src/deep/external.d.ts.map +1 -1
- package/dist/src/deep/get.bench.d.ts +2 -0
- package/dist/src/deep/get.bench.d.ts.map +1 -0
- package/dist/src/deep/get.d.ts +16 -0
- package/dist/src/deep/get.d.ts.map +1 -0
- package/dist/src/deep/get.spec.d.ts +2 -0
- package/dist/src/deep/get.spec.d.ts.map +1 -0
- package/dist/src/deep/partial.spec.d.ts +2 -0
- package/dist/src/deep/partial.spec.d.ts.map +1 -0
- package/dist/src/deep/path.d.ts +4 -92
- package/dist/src/deep/path.d.ts.map +1 -1
- package/dist/src/deep/remove.bench.d.ts +2 -0
- package/dist/src/deep/remove.bench.d.ts.map +1 -0
- package/dist/src/deep/remove.d.ts +2 -0
- package/dist/src/deep/remove.d.ts.map +1 -0
- package/dist/src/deep/remove.spec.d.ts +2 -0
- package/dist/src/deep/remove.spec.d.ts.map +1 -0
- package/dist/src/deep/set.bench.d.ts +2 -0
- package/dist/src/deep/set.bench.d.ts.map +1 -0
- package/dist/src/deep/set.d.ts +2 -0
- package/dist/src/deep/set.d.ts.map +1 -0
- package/dist/src/deep/set.spec.d.ts +2 -0
- package/dist/src/deep/set.spec.d.ts.map +1 -0
- package/dist/zod.cjs +1 -1
- package/dist/zod.js +1 -1
- package/package.json +2 -2
- package/src/deep/copy.spec.ts +148 -0
- package/src/deep/external.ts +3 -1
- package/src/deep/get.bench.ts +170 -0
- package/src/deep/get.spec.ts +196 -0
- package/src/deep/get.ts +79 -0
- package/src/deep/partial.spec.ts +194 -0
- package/src/deep/path.spec.ts +92 -183
- package/src/deep/path.ts +27 -198
- package/src/deep/remove.bench.ts +238 -0
- package/src/deep/remove.spec.ts +219 -0
- package/src/deep/remove.ts +102 -0
- package/src/deep/set.bench.ts +208 -0
- package/src/deep/set.spec.ts +369 -0
- package/src/deep/set.ts +91 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/external-E3ErJeeM.cjs +0 -1
- package/dist/path-Blh4wJuA.js +0 -110
- package/dist/path-CPSfCjde.cjs +0 -1
- package/dist/src/deep/delete.d.ts +0 -3
- package/dist/src/deep/delete.d.ts.map +0 -1
- package/dist/src/deep/delete.spec.d.ts +0 -2
- package/dist/src/deep/delete.spec.d.ts.map +0 -1
- package/src/deep/delete.spec.ts +0 -73
- package/src/deep/delete.ts +0 -27
|
@@ -0,0 +1,196 @@
|
|
|
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 { deep } from "@/deep";
|
|
13
|
+
import { type record } from "@/record";
|
|
14
|
+
|
|
15
|
+
interface TestRecord {
|
|
16
|
+
a: number;
|
|
17
|
+
b: {
|
|
18
|
+
c?: number;
|
|
19
|
+
d?: number;
|
|
20
|
+
};
|
|
21
|
+
c: number[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe("get", () => {
|
|
25
|
+
it("should get a key", () => {
|
|
26
|
+
const a: TestRecord = {
|
|
27
|
+
a: 1,
|
|
28
|
+
b: {
|
|
29
|
+
c: 2,
|
|
30
|
+
},
|
|
31
|
+
c: [1],
|
|
32
|
+
};
|
|
33
|
+
expect(deep.get(a, "b.c")).toEqual(2);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should get an array index", () => {
|
|
37
|
+
const a: TestRecord = {
|
|
38
|
+
a: 1,
|
|
39
|
+
b: {
|
|
40
|
+
c: 2,
|
|
41
|
+
},
|
|
42
|
+
c: [1, 2, 3],
|
|
43
|
+
};
|
|
44
|
+
expect(deep.get(a, "c.1")).toEqual(2);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should return the object itself if the key is empty", () => {
|
|
48
|
+
const a: TestRecord = {
|
|
49
|
+
a: 1,
|
|
50
|
+
b: {
|
|
51
|
+
c: 2,
|
|
52
|
+
},
|
|
53
|
+
c: [1, 2, 3],
|
|
54
|
+
};
|
|
55
|
+
expect(deep.get(a, "")).toStrictEqual(a);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("custom getter function", () => {
|
|
59
|
+
const v = {
|
|
60
|
+
a: {
|
|
61
|
+
value: () => ({
|
|
62
|
+
c: 0,
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
it("should use the custom getter function", () => {
|
|
67
|
+
expect(
|
|
68
|
+
deep.get(v, "a.value().c", {
|
|
69
|
+
optional: false,
|
|
70
|
+
getter: (obj, key) => {
|
|
71
|
+
if (key === "value()")
|
|
72
|
+
return (obj as { value: () => { c: number } }).value();
|
|
73
|
+
return obj[key];
|
|
74
|
+
},
|
|
75
|
+
}),
|
|
76
|
+
).toEqual(0);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should get an array of keyed records", () => {
|
|
80
|
+
interface TestKeyedRecord {
|
|
81
|
+
values: record.KeyedNamed[];
|
|
82
|
+
}
|
|
83
|
+
const a: TestKeyedRecord = {
|
|
84
|
+
values: [
|
|
85
|
+
{ key: "a", name: "a" },
|
|
86
|
+
{ key: "b", name: "b" },
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
expect(deep.get(a, "values.a.name")).toEqual("a");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("path includes a .", () => {
|
|
94
|
+
it("should get a value in case the path includes a period", () => {
|
|
95
|
+
const data = { "a.b": { c: 1 } };
|
|
96
|
+
expect(deep.get(data, "a.b.c")).toEqual(1);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should work with keys that contain a period", () => {
|
|
100
|
+
const data = {
|
|
101
|
+
channels: [
|
|
102
|
+
{ key: "key.period", color: "blue" },
|
|
103
|
+
{ key: "noPeriod", color: "red" },
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
expect(deep.get(data, "channels.key.period.color")).toEqual("blue");
|
|
107
|
+
expect(deep.get(data, "channels.noPeriod.color")).toEqual("red");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should handle null values in get", () => {
|
|
112
|
+
const obj = { a: null };
|
|
113
|
+
expect(deep.get(obj, "a")).toBeNull();
|
|
114
|
+
expect(deep.get(obj, "a.b", { optional: true })).toBeNull();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should handle undefined values in get", () => {
|
|
118
|
+
const obj = { a: undefined };
|
|
119
|
+
expect(deep.get(obj, "a", { optional: true })).toBeNull();
|
|
120
|
+
expect(deep.get(obj, "a.b", { optional: true })).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("should handle get with default value", () => {
|
|
124
|
+
const obj = { a: { b: 1 } };
|
|
125
|
+
const result = deep.get(obj, "a.c", { optional: true });
|
|
126
|
+
expect(result).toBeNull();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should handle numeric string keys", () => {
|
|
130
|
+
const obj = { "123": "numeric key" };
|
|
131
|
+
expect(deep.get(obj, "123")).toEqual("numeric key");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should handle special characters in keys", () => {
|
|
135
|
+
const obj = { "key-with-dash": 1, key_with_underscore: 2 };
|
|
136
|
+
expect(deep.get(obj, "key-with-dash")).toEqual(1);
|
|
137
|
+
expect(deep.get(obj, "key_with_underscore")).toEqual(2);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should handle boolean values in paths", () => {
|
|
141
|
+
const obj = { a: { true: "yes", false: "no" } };
|
|
142
|
+
expect(deep.get(obj, "a.true")).toEqual("yes");
|
|
143
|
+
expect(deep.get(obj, "a.false")).toEqual("no");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should handle very long paths", () => {
|
|
147
|
+
const longPath = new Array(100).fill("a").join(".");
|
|
148
|
+
const obj: any = {};
|
|
149
|
+
let current = obj;
|
|
150
|
+
for (let i = 0; i < 99; i++) {
|
|
151
|
+
current.a = {};
|
|
152
|
+
current = current.a;
|
|
153
|
+
}
|
|
154
|
+
current.a = "deep";
|
|
155
|
+
expect(deep.get(obj, longPath)).toEqual("deep");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should throw error when path doesn't exist and not optional", () => {
|
|
159
|
+
const obj = { a: { b: 1 } };
|
|
160
|
+
expect(() => deep.get(obj, "a.c.d")).toThrow();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("should return null when path doesn't exist and optional", () => {
|
|
164
|
+
const obj = { a: { b: 1 } };
|
|
165
|
+
expect(deep.get(obj, "a.c.d", { optional: true })).toBeNull();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe("has", () => {
|
|
170
|
+
it("should return true if path exists", () => {
|
|
171
|
+
const obj = { a: { b: { c: 1 } } };
|
|
172
|
+
expect(deep.has(obj, "a.b.c")).toBe(true);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("should return false if path doesn't exist", () => {
|
|
176
|
+
const obj = { a: { b: 1 } };
|
|
177
|
+
expect(deep.has(obj, "a.c")).toBe(false);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should handle arrays", () => {
|
|
181
|
+
const obj = { a: [1, 2, 3] };
|
|
182
|
+
expect(deep.has(obj, "a.1")).toBe(true);
|
|
183
|
+
expect(deep.has(obj, "a.5")).toBe(false);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("should handle keyed records in arrays", () => {
|
|
187
|
+
const obj = {
|
|
188
|
+
items: [
|
|
189
|
+
{ key: "item1", value: 1 },
|
|
190
|
+
{ key: "item2", value: 2 },
|
|
191
|
+
],
|
|
192
|
+
};
|
|
193
|
+
expect(deep.has(obj, "items.item1")).toBe(true);
|
|
194
|
+
expect(deep.has(obj, "items.item3")).toBe(false);
|
|
195
|
+
});
|
|
196
|
+
});
|
package/src/deep/get.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
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 { defaultGetter, SEPARATOR } from "@/deep/path";
|
|
11
|
+
import { type record } from "@/record";
|
|
12
|
+
|
|
13
|
+
export interface GetOptions<O extends boolean | undefined = boolean | undefined> {
|
|
14
|
+
optional: O;
|
|
15
|
+
getter?: (obj: record.Unknown, key: string) => unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Get {
|
|
19
|
+
<V = record.Unknown, T = record.Unknown>(
|
|
20
|
+
obj: T,
|
|
21
|
+
path: string,
|
|
22
|
+
options?: GetOptions<false>,
|
|
23
|
+
): V;
|
|
24
|
+
<V = record.Unknown, T = record.Unknown>(
|
|
25
|
+
obj: T,
|
|
26
|
+
path: string,
|
|
27
|
+
options?: GetOptions<boolean | undefined>,
|
|
28
|
+
): V | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface TypedGet<V = record.Unknown, T = record.Unknown> {
|
|
32
|
+
(obj: T, path: string, options?: GetOptions<false>): V;
|
|
33
|
+
(obj: T, path: string, options?: GetOptions<boolean | undefined>): V | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const get = (<V = record.Unknown, T = record.Unknown>(
|
|
37
|
+
obj: T,
|
|
38
|
+
path: string,
|
|
39
|
+
opts: GetOptions = { optional: false },
|
|
40
|
+
): V | null => {
|
|
41
|
+
const { optional, getter = defaultGetter } = opts;
|
|
42
|
+
if (path === "") return obj as record.Unknown as V;
|
|
43
|
+
|
|
44
|
+
const parts = path.split(SEPARATOR);
|
|
45
|
+
if (parts.length === 1) {
|
|
46
|
+
const v = getter(obj as record.Unknown, parts[0]);
|
|
47
|
+
if (v === undefined) {
|
|
48
|
+
if (optional) return null;
|
|
49
|
+
throw new Error(`Path ${path} does not exist. ${parts[0]} is undefined`);
|
|
50
|
+
}
|
|
51
|
+
return v as V;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const tryGet = (currentObj: record.Unknown, partIndex: number): V | null => {
|
|
55
|
+
if (partIndex >= parts.length) return currentObj as V;
|
|
56
|
+
|
|
57
|
+
for (let i = parts.length - partIndex; i >= 1; i--) {
|
|
58
|
+
const combinedKey = parts.slice(partIndex, partIndex + i).join(SEPARATOR);
|
|
59
|
+
const v = getter(currentObj, combinedKey);
|
|
60
|
+
if (v !== undefined) {
|
|
61
|
+
if (partIndex + i === parts.length) return v as V;
|
|
62
|
+
if (v === null) {
|
|
63
|
+
if (optional) return null;
|
|
64
|
+
throw new Error(`Path ${path} does not exist. ${combinedKey} is null`);
|
|
65
|
+
}
|
|
66
|
+
return tryGet(v as record.Unknown, partIndex + i);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (optional) return null;
|
|
70
|
+
throw new Error(`Path ${path} does not exist. ${parts[partIndex]} is undefined`);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return tryGet(obj as record.Unknown, 0);
|
|
74
|
+
}) as Get;
|
|
75
|
+
|
|
76
|
+
export const has = <V = record.Unknown, T = record.Unknown>(
|
|
77
|
+
obj: T,
|
|
78
|
+
path: string,
|
|
79
|
+
): boolean => get<V, T>(obj, path, { optional: true }) !== null;
|
|
@@ -0,0 +1,194 @@
|
|
|
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 { type deep } from "@/deep";
|
|
13
|
+
|
|
14
|
+
describe("Partial", () => {
|
|
15
|
+
it("should make all properties optional at first level", () => {
|
|
16
|
+
interface Test {
|
|
17
|
+
a: string;
|
|
18
|
+
b: number;
|
|
19
|
+
}
|
|
20
|
+
type PartialTest = deep.Partial<Test>;
|
|
21
|
+
const obj: PartialTest = {};
|
|
22
|
+
expect(obj).toEqual({});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should make nested object properties optional", () => {
|
|
26
|
+
interface Test {
|
|
27
|
+
a: {
|
|
28
|
+
b: string;
|
|
29
|
+
c: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
type PartialTest = deep.Partial<Test>;
|
|
33
|
+
const obj1: PartialTest = {};
|
|
34
|
+
const obj2: PartialTest = { a: {} };
|
|
35
|
+
const obj3: PartialTest = { a: { b: "test" } };
|
|
36
|
+
|
|
37
|
+
expect(obj1).toEqual({});
|
|
38
|
+
expect(obj2).toEqual({ a: {} });
|
|
39
|
+
expect(obj3).toEqual({ a: { b: "test" } });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should handle deeply nested objects", () => {
|
|
43
|
+
interface Test {
|
|
44
|
+
a: {
|
|
45
|
+
b: {
|
|
46
|
+
c: {
|
|
47
|
+
d: string;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
type PartialTest = deep.Partial<Test>;
|
|
53
|
+
const obj1: PartialTest = {};
|
|
54
|
+
const obj2: PartialTest = { a: { b: {} } };
|
|
55
|
+
const obj3: PartialTest = { a: { b: { c: { d: "test" } } } };
|
|
56
|
+
|
|
57
|
+
expect(obj1).toEqual({});
|
|
58
|
+
expect(obj2).toEqual({ a: { b: {} } });
|
|
59
|
+
expect(obj3).toEqual({ a: { b: { c: { d: "test" } } } });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should handle arrays", () => {
|
|
63
|
+
interface Test {
|
|
64
|
+
items: string[];
|
|
65
|
+
nested: {
|
|
66
|
+
values: number[];
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
type PartialTest = deep.Partial<Test>;
|
|
70
|
+
const obj1: PartialTest = {};
|
|
71
|
+
const obj2: PartialTest = { items: ["a", "b"] };
|
|
72
|
+
const obj3: PartialTest = { nested: { values: [1, 2, 3] } };
|
|
73
|
+
|
|
74
|
+
expect(obj1).toEqual({});
|
|
75
|
+
expect(obj2).toEqual({ items: ["a", "b"] });
|
|
76
|
+
expect(obj3).toEqual({ nested: { values: [1, 2, 3] } });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should handle primitive types", () => {
|
|
80
|
+
type StringPartial = deep.Partial<string>;
|
|
81
|
+
type NumberPartial = deep.Partial<number>;
|
|
82
|
+
type BooleanPartial = deep.Partial<boolean>;
|
|
83
|
+
|
|
84
|
+
const str: StringPartial = "test";
|
|
85
|
+
const num: NumberPartial = 42;
|
|
86
|
+
const bool: BooleanPartial = true;
|
|
87
|
+
|
|
88
|
+
expect(str).toBe("test");
|
|
89
|
+
expect(num).toBe(42);
|
|
90
|
+
expect(bool).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should handle union types", () => {
|
|
94
|
+
interface Test {
|
|
95
|
+
value: string | number;
|
|
96
|
+
nested: {
|
|
97
|
+
prop: boolean | null;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
type PartialTest = deep.Partial<Test>;
|
|
101
|
+
const obj1: PartialTest = {};
|
|
102
|
+
const obj2: PartialTest = { value: "test" };
|
|
103
|
+
const obj3: PartialTest = { value: 42 };
|
|
104
|
+
const obj4: PartialTest = { nested: { prop: null } };
|
|
105
|
+
|
|
106
|
+
expect(obj1).toEqual({});
|
|
107
|
+
expect(obj2).toEqual({ value: "test" });
|
|
108
|
+
expect(obj3).toEqual({ value: 42 });
|
|
109
|
+
expect(obj4).toEqual({ nested: { prop: null } });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should handle optional properties", () => {
|
|
113
|
+
interface Test {
|
|
114
|
+
required: string;
|
|
115
|
+
optional?: number;
|
|
116
|
+
nested: {
|
|
117
|
+
req: boolean;
|
|
118
|
+
opt?: string;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
type PartialTest = deep.Partial<Test>;
|
|
122
|
+
const obj: PartialTest = {
|
|
123
|
+
nested: {
|
|
124
|
+
req: true
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
expect(obj).toEqual({ nested: { req: true } });
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("should handle Record types", () => {
|
|
132
|
+
interface Test {
|
|
133
|
+
data: Record<string, number>;
|
|
134
|
+
}
|
|
135
|
+
type PartialTest = deep.Partial<Test>;
|
|
136
|
+
const obj1: PartialTest = {};
|
|
137
|
+
const obj2: PartialTest = { data: { a: 1, b: 2 } };
|
|
138
|
+
|
|
139
|
+
expect(obj1).toEqual({});
|
|
140
|
+
expect(obj2).toEqual({ data: { a: 1, b: 2 } });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should handle tuples", () => {
|
|
144
|
+
interface Test {
|
|
145
|
+
tuple: [string, number, boolean];
|
|
146
|
+
}
|
|
147
|
+
type PartialTest = deep.Partial<Test>;
|
|
148
|
+
const obj1: PartialTest = {};
|
|
149
|
+
const obj2: PartialTest = { tuple: ["a", 1, true] };
|
|
150
|
+
|
|
151
|
+
expect(obj1).toEqual({});
|
|
152
|
+
expect(obj2).toEqual({ tuple: ["a", 1, true] });
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("should compile with complex nested structures", () => {
|
|
156
|
+
interface Complex {
|
|
157
|
+
id: string;
|
|
158
|
+
metadata: {
|
|
159
|
+
created: Date;
|
|
160
|
+
modified: Date;
|
|
161
|
+
tags: string[];
|
|
162
|
+
};
|
|
163
|
+
content: {
|
|
164
|
+
title: string;
|
|
165
|
+
body: {
|
|
166
|
+
paragraphs: Array<{
|
|
167
|
+
text: string;
|
|
168
|
+
style?: {
|
|
169
|
+
bold?: boolean;
|
|
170
|
+
italic?: boolean;
|
|
171
|
+
};
|
|
172
|
+
}>;
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
type PartialComplex = deep.Partial<Complex>;
|
|
178
|
+
const obj: PartialComplex = {
|
|
179
|
+
content: {
|
|
180
|
+
body: {
|
|
181
|
+
paragraphs: [{ text: "test" }]
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
expect(obj).toEqual({
|
|
187
|
+
content: {
|
|
188
|
+
body: {
|
|
189
|
+
paragraphs: [{ text: "test" }]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
});
|