-
Notifications
You must be signed in to change notification settings - Fork 1
/
list-diff.ts
128 lines (106 loc) · 3.05 KB
/
list-diff.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import { simpleObjDiff } from "./obj-diff"
import { basicDiffParams, hasValForArray, invariant } from "./utils"
export type ListKey = string | number
export interface SimpleListDiffOptions {
key: string
getChangedItem?: (params: {
newLine: any,
oldLine: any,
}) => any
sortName?: string;
}
const DEFAULT_OPTIONS: SimpleListDiffOptions = {
key: 'id',
}
const checkOptions = (opts: SimpleListDiffOptions) => {
const { key, getChangedItem } = opts
invariant(typeof key !== 'string' || key.length === 0, 'options "key" must be a no empty string')
invariant(!!getChangedItem && typeof getChangedItem !== 'function', 'options "getChangedItem" must be a function')
}
interface SimpleObjDiffParams extends basicDiffParams<any[]> {
options: SimpleListDiffOptions
}
export const simpleListDiff = ({
newVal, oldVal, options
}: SimpleObjDiffParams) => {
invariant(!Array.isArray(newVal), 'params newVal must be a Array')
invariant(!Array.isArray(oldVal), 'params oldVal must be a Array')
const opts = { ...DEFAULT_OPTIONS, ...options }
checkOptions(opts)
const { key, sortName = '' } = opts
const hasSortName: boolean = typeof sortName === 'string' && sortName.length > 0
let { getChangedItem } = opts;
if (!getChangedItem) {
getChangedItem = ({
newLine,
oldLine,
}) => {
const result = simpleObjDiff({
newVal: newLine,
oldVal: oldLine,
});
if (!Object.keys(result).length) {
return null;
}
return { [key]: newLine[key], ...result };
}
}
if (!hasValForArray(oldVal)) {
return {
addedLines: newVal.map(item => ({
...item,
})),
deletedLines: [],
modifiedLines: [],
...hasSortName && { noChangeLines: [] },
}
}
// 设定增删改数
const addedLines: any[] = [];
const deletedLines: any[] = [];
const modifiedLines: any[] = [];
const noChangeLines: any[] = [];
const checkedKeys: Set<ListKey> = new Set<ListKey>();
newVal.forEach((newLine, index: number) => {
let oldLineIndex: any = oldVal.findIndex(x => x[key] === newLine[key])
if (oldLineIndex === -1) {
addedLines.push({
...newLine,
...hasSortName && { [sortName]: index + 1 }
})
} else {
const oldLine = oldVal[oldLineIndex]
const addSortParams = hasSortName && index !== oldLineIndex
checkedKeys.add(oldLine[key])
const result = getChangedItem!({
newLine,
oldLine
})
if (result !== null && result !== undefined) {
modifiedLines.push({
...result,
...addSortParams && {[sortName]: index + 1}
})
} else {
if (addSortParams) {
noChangeLines.push({
[key!]: newLine[key!],
[sortName]: index + 1,
})
}
}
}
})
oldVal.forEach(oldLine => {
if (checkedKeys.has(oldLine[key])) {
return
}
deletedLines.push({ [key]: oldLine[key] })
})
return {
addedLines,
deletedLines,
modifiedLines,
...hasSortName && { noChangeLines },
}
}