@potmot/diff 0.0.0 → 0.0.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/README.md +263 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +70 -58
- package/dist/index.umd.cjs +1 -1
- package/dist/type/DiffItem.d.ts +5 -5
- package/package.json +16 -4
package/README.md
CHANGED
|
@@ -23,3 +23,266 @@ yarn add @potmot/diff
|
|
|
23
23
|
```bash
|
|
24
24
|
pnpm add @potmot/diff
|
|
25
25
|
```
|
|
26
|
+
|
|
27
|
+
## 使用方法
|
|
28
|
+
|
|
29
|
+
### 1. deepEquals - 深度相等比较
|
|
30
|
+
|
|
31
|
+
用于深度比较两个值是否相等,支持对象、数组和嵌套结构。
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { deepEquals } from '@potmot/diff';
|
|
35
|
+
|
|
36
|
+
// 基本类型比较
|
|
37
|
+
deepEquals(1, 1); // true
|
|
38
|
+
deepEquals('hello', 'world'); // false
|
|
39
|
+
|
|
40
|
+
// 对象比较
|
|
41
|
+
deepEquals({ a: 1, b: 2 }, { a: 1, b: 2 }); // true
|
|
42
|
+
deepEquals({ a: 1 }, { a: 1, b: 2 }); // false
|
|
43
|
+
|
|
44
|
+
// 嵌套对象比较
|
|
45
|
+
deepEquals({ a: { b: { c: 1 } } }, { a: { b: { c: 1 } } }); // true
|
|
46
|
+
|
|
47
|
+
// 数组比较
|
|
48
|
+
deepEquals([1, 2, 3], [1, 2, 3]); // true
|
|
49
|
+
deepEquals([1, 2], [1, 2, 3]); // false
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. objectDiff - 对象差异分析
|
|
53
|
+
|
|
54
|
+
比较两个对象的差异,返回新增、删除和更新的属性。
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { objectDiff } from '@potmot/diff';
|
|
58
|
+
|
|
59
|
+
// 基本使用
|
|
60
|
+
const oldObj = { a: 1, b: 2, c: 3 };
|
|
61
|
+
const newObj = { a: 1, b: 4, d: 5 };
|
|
62
|
+
|
|
63
|
+
const result = objectDiff(oldObj, newObj);
|
|
64
|
+
/*
|
|
65
|
+
result = {
|
|
66
|
+
type: 'object',
|
|
67
|
+
deleted: {
|
|
68
|
+
c: { propertyName: 'c', value: 3 }
|
|
69
|
+
},
|
|
70
|
+
added: {
|
|
71
|
+
d: { propertyName: 'd', value: 5 }
|
|
72
|
+
},
|
|
73
|
+
updated: {
|
|
74
|
+
b: {
|
|
75
|
+
propertyName: 'b',
|
|
76
|
+
prevValue: 2,
|
|
77
|
+
nextValue: 4,
|
|
78
|
+
diff: undefined
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
// 嵌套对象比较
|
|
85
|
+
const oldUser = {
|
|
86
|
+
name: 'John',
|
|
87
|
+
address: {
|
|
88
|
+
city: 'Beijing',
|
|
89
|
+
zip: '100000'
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const newUser = {
|
|
94
|
+
name: 'John',
|
|
95
|
+
address: {
|
|
96
|
+
city: 'Shanghai',
|
|
97
|
+
zip: '100000'
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const diff = objectDiff(oldUser, newUser);
|
|
102
|
+
/*
|
|
103
|
+
diff = {
|
|
104
|
+
type: 'object',
|
|
105
|
+
updated: {
|
|
106
|
+
address: {
|
|
107
|
+
propertyName: 'address',
|
|
108
|
+
prevValue: { city: 'Beijing', zip: '100000' },
|
|
109
|
+
nextValue: { city: 'Shanghai', zip: '100000' },
|
|
110
|
+
diff: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
updated: {
|
|
113
|
+
city: {
|
|
114
|
+
propertyName: 'city',
|
|
115
|
+
prevValue: 'Beijing',
|
|
116
|
+
nextValue: 'Shanghai',
|
|
117
|
+
diff: undefined
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
// 处理 null/undefined
|
|
127
|
+
objectDiff(null, { a: 1 }); // 所有属性都是新增
|
|
128
|
+
objectDiff({ a: 1 }, null); // 所有属性都是删除
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 3. arrayDiff - 数组差异分析
|
|
132
|
+
|
|
133
|
+
比较两个数组的差异,支持元素新增、删除、更新和移动检测。
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { arrayDiff } from '@potmot/diff';
|
|
137
|
+
|
|
138
|
+
// 定义匹配函数(用于识别同一元素)
|
|
139
|
+
const matchById = (a, b) => a.id === b.id;
|
|
140
|
+
|
|
141
|
+
const oldList = [
|
|
142
|
+
{ id: 1, name: 'Item 1', value: 'A' },
|
|
143
|
+
{ id: 2, name: 'Item 2', value: 'B' },
|
|
144
|
+
{ id: 3, name: 'Item 3', value: 'C' }
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
const newList = [
|
|
148
|
+
{ id: 2, name: 'Item 2', value: 'B' }, // 相等
|
|
149
|
+
{ id: 1, name: 'Item 1', value: 'A Updated' }, // 更新
|
|
150
|
+
{ id: 4, name: 'Item 4', value: 'D' } // 新增
|
|
151
|
+
// id: 3 被删除
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
const result = arrayDiff(oldList, newList, [matchById]);
|
|
155
|
+
/*
|
|
156
|
+
result = {
|
|
157
|
+
type: 'array',
|
|
158
|
+
added: [
|
|
159
|
+
{ data: { id: 4, name: 'Item 4', value: 'D' }, nextIndex: 2 }
|
|
160
|
+
],
|
|
161
|
+
updated: [
|
|
162
|
+
{
|
|
163
|
+
prevData: { id: 1, name: 'Item 1', value: 'A' },
|
|
164
|
+
prevIndex: 0,
|
|
165
|
+
nextData: { id: 1, name: 'Item 1', value: 'A Updated' },
|
|
166
|
+
nextIndex: 1,
|
|
167
|
+
diff: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
updated: {
|
|
170
|
+
value: {
|
|
171
|
+
propertyName: 'value',
|
|
172
|
+
prevValue: 'A',
|
|
173
|
+
nextValue: 'A Updated',
|
|
174
|
+
diff: undefined
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
deleted: [
|
|
181
|
+
{ data: { id: 3, name: 'Item 3', value: 'C' }, prevIndex: 2 }
|
|
182
|
+
],
|
|
183
|
+
moved: [
|
|
184
|
+
{ data: { id: 2, name: 'Item 2', value: 'B' }, prevIndex: 1, nextIndex: 0 }
|
|
185
|
+
],
|
|
186
|
+
equals: []
|
|
187
|
+
}
|
|
188
|
+
*/
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 4. 高级用法
|
|
192
|
+
|
|
193
|
+
#### 多条件匹配
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// 使用多个匹配函数进行更精确的对比
|
|
197
|
+
const matchByNameAndValue = [
|
|
198
|
+
(a, b) => a.name === b.name,
|
|
199
|
+
(a, b) => a.value === b.value
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
const result = arrayDiff(oldList, newList, matchByNameAndValue);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### 自定义深度比较函数
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// 为 objectDiff 提供自定义的深度比较函数
|
|
209
|
+
const customDeepMatch = [
|
|
210
|
+
(a, b) => {
|
|
211
|
+
// 如果都有 name 属性,则通过 name 判断是否相等
|
|
212
|
+
if ('name' in a && 'name' in b) {
|
|
213
|
+
return a.name === b.name;
|
|
214
|
+
}
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
const result = objectDiff(oldObj, newObj, customDeepMatch);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### 循环引用处理
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// 自动检测和处理循环引用
|
|
226
|
+
const obj1 = { a: 1 };
|
|
227
|
+
obj1.self = obj1; // 循环引用
|
|
228
|
+
|
|
229
|
+
const obj2 = { a: 2 };
|
|
230
|
+
obj2.self = obj2; // 循环引用
|
|
231
|
+
|
|
232
|
+
const result = objectDiff(obj1, obj2);
|
|
233
|
+
// {
|
|
234
|
+
// type: 'object',
|
|
235
|
+
// updated: {
|
|
236
|
+
// a: { propertyName: 'a', prevValue: 1, nextValue: 2, diff: undefined },
|
|
237
|
+
// self: {
|
|
238
|
+
// propertyName: 'self',
|
|
239
|
+
// prevValue: obj1,
|
|
240
|
+
// nextValue: obj2,
|
|
241
|
+
// diff: { type: 'circular reference' }
|
|
242
|
+
// }
|
|
243
|
+
// }
|
|
244
|
+
// }
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## API 参考
|
|
248
|
+
|
|
249
|
+
### deepEquals(a: any, b: any): boolean
|
|
250
|
+
|
|
251
|
+
深度比较两个值是否相等。
|
|
252
|
+
|
|
253
|
+
**参数:**
|
|
254
|
+
- `a` - 第一个值
|
|
255
|
+
- `b` - 第二个值
|
|
256
|
+
|
|
257
|
+
**返回:** `boolean` - 如果两个值深度相等则返回 `true`
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### objectDiff<T, U>(oldVal: T | undefined | null, newVal: U | undefined | null, deepMatchFnList?: Function[]): ObjectDiff | CircularReferenceDiff
|
|
262
|
+
|
|
263
|
+
比较两个对象的差异。
|
|
264
|
+
|
|
265
|
+
**参数:**
|
|
266
|
+
- `oldVal` - 原始对象
|
|
267
|
+
- `newVal` - 新对象
|
|
268
|
+
- `deepMatchFnList` - 可选,自定义深度比较函数列表,默认匹配函数为`deepEquals`
|
|
269
|
+
|
|
270
|
+
**返回:** `ObjectDiff | CircularReferenceDiff` - 差异结果对象
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
### arrayDiff<T>(prevList: T[], nextList: T[], matchFnList: Function[], deepMatchFnList?: Function[]): ArrayDiff
|
|
275
|
+
|
|
276
|
+
比较两个数组的差异。
|
|
277
|
+
|
|
278
|
+
**参数:**
|
|
279
|
+
- `prevList` - 原始数组
|
|
280
|
+
- `nextList` - 新数组
|
|
281
|
+
- `matchFnList` - 匹配函数列表,用于识别同一元素
|
|
282
|
+
- `deepMatchFnList` - 可选,自定义深度比较函数列表,默认匹配函数为`deepEquals`
|
|
283
|
+
|
|
284
|
+
**返回:** `ArrayDiff` - 差异结果对象,包含 `added`、`updated`、`deleted`、`moved`、`equals` 数组
|
|
285
|
+
|
|
286
|
+
## 许可证
|
|
287
|
+
|
|
288
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type { CircularReferenceDiff, ObjectDiff, PropertyAddedDiffItem, PropertyDeletedDiffItem, PropertyUpdatedDiffItem, ArrayDiff, ArrayAddedDiffItem, ArrayUpdatedDiffItem, ArrayDeletedDiffItem, ArrayMovedDiffItem, ArrayEqualsDiffItem, } from './type/DiffItem';
|
|
1
2
|
export { deepEquals } from './deepEquals';
|
|
2
3
|
export { arrayDiff } from './arrayDiff';
|
|
3
4
|
export { objectDiff } from './objectDiff';
|
package/dist/index.js
CHANGED
|
@@ -10,21 +10,21 @@ const j = (t, e) => {
|
|
|
10
10
|
if (Array.isArray(t) && Array.isArray(e)) {
|
|
11
11
|
if (t.length !== e.length)
|
|
12
12
|
return !1;
|
|
13
|
-
for (let
|
|
14
|
-
if (!j(t[
|
|
13
|
+
for (let c = 0; c < t.length; c++)
|
|
14
|
+
if (!j(t[c], e[c]))
|
|
15
15
|
return !1;
|
|
16
16
|
return !0;
|
|
17
17
|
}
|
|
18
18
|
if (Array.isArray(t) || Array.isArray(e))
|
|
19
19
|
return !1;
|
|
20
|
-
const
|
|
21
|
-
if (
|
|
20
|
+
const y = Object.keys(t), u = Object.keys(e);
|
|
21
|
+
if (y.length !== u.length)
|
|
22
22
|
return !1;
|
|
23
|
-
for (const
|
|
24
|
-
if (!
|
|
23
|
+
for (const c of y)
|
|
24
|
+
if (!u.includes(c) || !j(t[c], e[c]))
|
|
25
25
|
return !1;
|
|
26
26
|
return !0;
|
|
27
|
-
},
|
|
27
|
+
}, l = (t, e, y = [j], u = /* @__PURE__ */ new WeakSet(), c = /* @__PURE__ */ new WeakSet()) => {
|
|
28
28
|
if ((t == null || Object.keys(t).length === 0) && (e == null || Object.keys(e).length === 0))
|
|
29
29
|
return { type: "object" };
|
|
30
30
|
if (t == null || typeof t != "object") {
|
|
@@ -48,47 +48,53 @@ const j = (t, e) => {
|
|
|
48
48
|
}), { type: "object", deleted: r };
|
|
49
49
|
}
|
|
50
50
|
if (typeof t == "object") {
|
|
51
|
-
if (
|
|
51
|
+
if (u.has(t))
|
|
52
52
|
return { type: "circular reference" };
|
|
53
|
-
|
|
53
|
+
u.add(t);
|
|
54
54
|
}
|
|
55
55
|
if (typeof e == "object") {
|
|
56
|
-
if (
|
|
56
|
+
if (c.has(e))
|
|
57
57
|
return { type: "circular reference" };
|
|
58
|
-
|
|
58
|
+
c.add(e);
|
|
59
59
|
}
|
|
60
|
-
const
|
|
60
|
+
const h = { type: "object" }, i = {};
|
|
61
61
|
for (const r in t)
|
|
62
|
-
r in e || (
|
|
62
|
+
r in e || (i[r] = {
|
|
63
63
|
propertyName: r,
|
|
64
64
|
value: t[r]
|
|
65
65
|
});
|
|
66
|
-
Object.keys(
|
|
67
|
-
const
|
|
66
|
+
Object.keys(i).length > 0 && (h.deleted = i);
|
|
67
|
+
const p = {};
|
|
68
68
|
for (const r in e)
|
|
69
|
-
r in t || (
|
|
69
|
+
r in t || (p[r] = {
|
|
70
70
|
propertyName: r,
|
|
71
71
|
value: e[r]
|
|
72
72
|
});
|
|
73
|
-
Object.keys(
|
|
74
|
-
const
|
|
73
|
+
Object.keys(p).length > 0 && (h.added = p);
|
|
74
|
+
const a = {};
|
|
75
75
|
for (const r in t)
|
|
76
76
|
if (r in e) {
|
|
77
77
|
const f = r, n = r;
|
|
78
78
|
if (!j(t[f], e[n])) {
|
|
79
|
-
const
|
|
80
|
-
let
|
|
81
|
-
Array.isArray(
|
|
79
|
+
const s = t[f], d = e[n];
|
|
80
|
+
let o;
|
|
81
|
+
Array.isArray(s) && Array.isArray(d) ? o = x(s, d, y, y) : s !== null && d !== null && s !== void 0 && d !== void 0 && typeof s == "object" && typeof d == "object" && (o = l(
|
|
82
|
+
s,
|
|
83
|
+
d,
|
|
84
|
+
y,
|
|
85
|
+
u,
|
|
86
|
+
c
|
|
87
|
+
)), a[r] = {
|
|
82
88
|
propertyName: r,
|
|
83
89
|
prevValue: t[f],
|
|
84
90
|
nextValue: e[n],
|
|
85
|
-
diff:
|
|
91
|
+
diff: o
|
|
86
92
|
};
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
|
-
return Object.keys(
|
|
90
|
-
}, x = (t, e,
|
|
91
|
-
const
|
|
95
|
+
return Object.keys(a).length > 0 && (h.updated = a), h;
|
|
96
|
+
}, x = (t, e, y, u = [j], c = /* @__PURE__ */ new WeakSet(), h = /* @__PURE__ */ new WeakSet()) => {
|
|
97
|
+
const i = {
|
|
92
98
|
type: "array",
|
|
93
99
|
added: [],
|
|
94
100
|
updated: [],
|
|
@@ -97,54 +103,60 @@ const j = (t, e) => {
|
|
|
97
103
|
equals: []
|
|
98
104
|
};
|
|
99
105
|
if (!t && !e)
|
|
100
|
-
return
|
|
106
|
+
return i;
|
|
101
107
|
if (!t)
|
|
102
108
|
return e?.forEach((r, f) => {
|
|
103
|
-
|
|
104
|
-
}),
|
|
109
|
+
i.added.push({ data: r, nextIndex: f });
|
|
110
|
+
}), i;
|
|
105
111
|
if (!e)
|
|
106
112
|
return t?.forEach((r, f) => {
|
|
107
|
-
|
|
108
|
-
}),
|
|
109
|
-
const
|
|
110
|
-
for (const r of
|
|
111
|
-
for (const f of
|
|
112
|
-
const { item: n, index:
|
|
113
|
+
i.deleted.push({ data: r, prevIndex: f });
|
|
114
|
+
}), i;
|
|
115
|
+
const p = new Set(t.map((r, f) => ({ item: r, index: f }))), a = new Set(e.map((r, f) => ({ item: r, index: f })));
|
|
116
|
+
for (const r of y)
|
|
117
|
+
for (const f of p) {
|
|
118
|
+
const { item: n, index: s } = f;
|
|
113
119
|
let d;
|
|
114
|
-
for (const
|
|
115
|
-
r(n,
|
|
120
|
+
for (const o of a)
|
|
121
|
+
r(n, o.item) && (d = o);
|
|
116
122
|
if (d !== void 0) {
|
|
117
|
-
const { item:
|
|
118
|
-
if (j(n,
|
|
119
|
-
|
|
120
|
-
data:
|
|
121
|
-
index:
|
|
122
|
-
}) :
|
|
123
|
-
data:
|
|
124
|
-
prevIndex:
|
|
125
|
-
nextIndex:
|
|
123
|
+
const { item: o, index: v } = d;
|
|
124
|
+
if (j(n, o))
|
|
125
|
+
s === v ? i.equals.push({
|
|
126
|
+
data: o,
|
|
127
|
+
index: v
|
|
128
|
+
}) : i.moved.push({
|
|
129
|
+
data: o,
|
|
130
|
+
prevIndex: s,
|
|
131
|
+
nextIndex: v
|
|
126
132
|
});
|
|
127
133
|
else {
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
let k;
|
|
135
|
+
Array.isArray(n) && Array.isArray(o) ? k = x(n, o, u, u) : n !== null && o !== null && n !== void 0 && o !== void 0 && typeof n == "object" && typeof o == "object" && (k = l(
|
|
136
|
+
n,
|
|
137
|
+
o,
|
|
138
|
+
u,
|
|
139
|
+
c,
|
|
140
|
+
h
|
|
141
|
+
)), i.updated.push({
|
|
130
142
|
prevData: n,
|
|
131
|
-
prevIndex:
|
|
132
|
-
nextData:
|
|
133
|
-
nextIndex:
|
|
134
|
-
diff:
|
|
143
|
+
prevIndex: s,
|
|
144
|
+
nextData: o,
|
|
145
|
+
nextIndex: v,
|
|
146
|
+
diff: k
|
|
135
147
|
});
|
|
136
148
|
}
|
|
137
|
-
|
|
149
|
+
p.delete(f), a.delete(d);
|
|
138
150
|
}
|
|
139
151
|
}
|
|
140
|
-
return
|
|
141
|
-
|
|
142
|
-
}),
|
|
143
|
-
|
|
144
|
-
}),
|
|
152
|
+
return p.forEach(({ item: r, index: f }) => {
|
|
153
|
+
i.deleted.push({ data: r, prevIndex: f });
|
|
154
|
+
}), a.forEach(({ item: r, index: f }) => {
|
|
155
|
+
i.added.push({ data: r, nextIndex: f });
|
|
156
|
+
}), i;
|
|
145
157
|
};
|
|
146
158
|
export {
|
|
147
159
|
x as arrayDiff,
|
|
148
160
|
j as deepEquals,
|
|
149
|
-
|
|
161
|
+
l as objectDiff
|
|
150
162
|
};
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(p,u){typeof exports=="object"&&typeof module<"u"?u(exports):typeof define=="function"&&define.amd?define(["exports"],u):(p=typeof globalThis<"u"?globalThis:p||self,u(p["@potmot/diff"]={}))})(this,(function(p){"use strict";const u=(t,e)=>{if(t===e)return!0;if(t===null||e===null||t===void 0||e===void 0)return t===e;if(typeof t!=typeof e)return!1;if(typeof t!="object")return t===e;if(Array.isArray(t)&&Array.isArray(e)){if(t.length!==e.length)return!1;for(let
|
|
1
|
+
(function(p,u){typeof exports=="object"&&typeof module<"u"?u(exports):typeof define=="function"&&define.amd?define(["exports"],u):(p=typeof globalThis<"u"?globalThis:p||self,u(p["@potmot/diff"]={}))})(this,(function(p){"use strict";const u=(t,e)=>{if(t===e)return!0;if(t===null||e===null||t===void 0||e===void 0)return t===e;if(typeof t!=typeof e)return!1;if(typeof t!="object")return t===e;if(Array.isArray(t)&&Array.isArray(e)){if(t.length!==e.length)return!1;for(let d=0;d<t.length;d++)if(!u(t[d],e[d]))return!1;return!0}if(Array.isArray(t)||Array.isArray(e))return!1;const a=Object.keys(t),s=Object.keys(e);if(a.length!==s.length)return!1;for(const d of a)if(!s.includes(d)||!u(t[d],e[d]))return!1;return!0},k=(t,e,a=[u],s=new WeakSet,d=new WeakSet)=>{if((t==null||Object.keys(t).length===0)&&(e==null||Object.keys(e).length===0))return{type:"object"};if(t==null||typeof t!="object"){const r={};return e!=null&&typeof e=="object"&&Object.keys(e).forEach(f=>{const n=f;r[n]={propertyName:n,value:e[n]}}),{type:"object",added:r}}if(e==null||typeof e!="object"){const r={};return Object.keys(t).forEach(f=>{const n=f;r[n]={propertyName:n,value:t[n]}}),{type:"object",deleted:r}}if(typeof t=="object"){if(s.has(t))return{type:"circular reference"};s.add(t)}if(typeof e=="object"){if(d.has(e))return{type:"circular reference"};d.add(e)}const l={type:"object"},i={};for(const r in t)r in e||(i[r]={propertyName:r,value:t[r]});Object.keys(i).length>0&&(l.deleted=i);const h={};for(const r in e)r in t||(h[r]={propertyName:r,value:e[r]});Object.keys(h).length>0&&(l.added=h);const j={};for(const r in t)if(r in e){const f=r,n=r;if(!u(t[f],e[n])){const y=t[f],c=e[n];let o;Array.isArray(y)&&Array.isArray(c)?o=m(y,c,a,a):y!==null&&c!==null&&y!==void 0&&c!==void 0&&typeof y=="object"&&typeof c=="object"&&(o=k(y,c,a,s,d)),j[r]={propertyName:r,prevValue:t[f],nextValue:e[n],diff:o}}}return Object.keys(j).length>0&&(l.updated=j),l},m=(t,e,a,s=[u],d=new WeakSet,l=new WeakSet)=>{const i={type:"array",added:[],updated:[],deleted:[],moved:[],equals:[]};if(!t&&!e)return i;if(!t)return e?.forEach((r,f)=>{i.added.push({data:r,nextIndex:f})}),i;if(!e)return t?.forEach((r,f)=>{i.deleted.push({data:r,prevIndex:f})}),i;const h=new Set(t.map((r,f)=>({item:r,index:f}))),j=new Set(e.map((r,f)=>({item:r,index:f})));for(const r of a)for(const f of h){const{item:n,index:y}=f;let c;for(const o of j)r(n,o.item)&&(c=o);if(c!==void 0){const{item:o,index:v}=c;if(u(n,o))y===v?i.equals.push({data:o,index:v}):i.moved.push({data:o,prevIndex:y,nextIndex:v});else{let b;Array.isArray(n)&&Array.isArray(o)?b=m(n,o,s,s):n!==null&&o!==null&&n!==void 0&&o!==void 0&&typeof n=="object"&&typeof o=="object"&&(b=k(n,o,s,d,l)),i.updated.push({prevData:n,prevIndex:y,nextData:o,nextIndex:v,diff:b})}h.delete(f),j.delete(c)}}return h.forEach(({item:r,index:f})=>{i.deleted.push({data:r,prevIndex:f})}),j.forEach(({item:r,index:f})=>{i.added.push({data:r,nextIndex:f})}),i};p.arrayDiff=m,p.deepEquals=u,p.objectDiff=k,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/type/DiffItem.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export type CircularReferenceDiff = {
|
|
2
|
-
type:
|
|
2
|
+
type: 'circular reference';
|
|
3
3
|
};
|
|
4
4
|
export type ObjectDiff<T extends Record<string, unknown>, U extends Record<string, unknown> = T> = {
|
|
5
|
-
type:
|
|
5
|
+
type: 'object';
|
|
6
6
|
updated?: {
|
|
7
7
|
[K in keyof T & keyof U]?: PropertyUpdatedDiffItem<T, U, K>;
|
|
8
8
|
};
|
|
@@ -21,11 +21,11 @@ export type PropertyDeletedDiffItem<T extends Record<string, unknown>, K extends
|
|
|
21
21
|
propertyName: K;
|
|
22
22
|
value: T[K];
|
|
23
23
|
};
|
|
24
|
-
export type PropertyUpdatedDiffItem<T extends Record<string, unknown>, U extends Record<string, unknown> = T, K extends
|
|
24
|
+
export type PropertyUpdatedDiffItem<T extends Record<string, unknown>, U extends Record<string, unknown> = T, K extends keyof T & keyof U = keyof T & keyof U> = {
|
|
25
25
|
propertyName: K;
|
|
26
26
|
prevValue: T[K];
|
|
27
27
|
nextValue: U[K];
|
|
28
|
-
diff?:
|
|
28
|
+
diff?: T[K] & U[K] extends Array<infer Item> | ReadonlyArray<infer Item> ? ArrayDiff<Item> : T[K] & U[K] extends Record<string, unknown> ? ObjectDiff<T[K] & U[K], T[K] & U[K]> | CircularReferenceDiff : never;
|
|
29
29
|
};
|
|
30
30
|
export type ArrayAddedDiffItem<T> = {
|
|
31
31
|
data: T;
|
|
@@ -52,7 +52,7 @@ export type ArrayEqualsDiffItem<T> = {
|
|
|
52
52
|
index: number;
|
|
53
53
|
};
|
|
54
54
|
export type ArrayDiff<T> = {
|
|
55
|
-
type:
|
|
55
|
+
type: 'array';
|
|
56
56
|
added: ArrayAddedDiffItem<T>[];
|
|
57
57
|
updated: ArrayUpdatedDiffItem<T>[];
|
|
58
58
|
deleted: ArrayDeletedDiffItem<T>[];
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@potmot/diff",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.1",
|
|
5
5
|
"description": "Lightweight deep diff tool for JavaScript objects and arrays.",
|
|
6
|
-
"keywords": [
|
|
6
|
+
"keywords": [
|
|
7
|
+
"diff"
|
|
8
|
+
],
|
|
7
9
|
"homepage": "https://github.com/pot-mot/diff/blob/main/README.md",
|
|
8
10
|
"repository": {
|
|
9
11
|
"type": "git",
|
|
@@ -37,14 +39,24 @@
|
|
|
37
39
|
},
|
|
38
40
|
"scripts": {
|
|
39
41
|
"build": "tsc & vite build",
|
|
40
|
-
"test": "vitest run"
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"lint:pritter": "prettier --write src/"
|
|
44
|
+
},
|
|
45
|
+
"lint-staged": {
|
|
46
|
+
"*.{js,ts,vue,json,css}": [
|
|
47
|
+
"prettier --write"
|
|
48
|
+
]
|
|
41
49
|
},
|
|
42
50
|
"devDependencies": {
|
|
43
51
|
"@tsconfig/node22": "^22.0.5",
|
|
44
52
|
"@types/node": "^25.2.3",
|
|
53
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
54
|
+
"husky": "^9.1.7",
|
|
55
|
+
"lint-staged": "^16.2.7",
|
|
56
|
+
"prettier": "^3.8.1",
|
|
45
57
|
"typescript": "~5.9.3",
|
|
46
58
|
"vite": "^7.3.1",
|
|
47
59
|
"vite-plugin-dts": "^4.5.4",
|
|
48
|
-
"vitest": "^
|
|
60
|
+
"vitest": "^3.2.4"
|
|
49
61
|
}
|
|
50
62
|
}
|