@chendf/data-compare v1.4.5
data-compare
data-compare是一个对比数据之间差异的一个轻量级库,类似于简化版本的git对比。
功能
通过diff算法对比出两个版本数据或三个版本数据之间的属性差异与状态。(新增/删除/修改/交换位置/冲突)。 通过diff算法对比出两个数据之间的属性差异。是否有属性删除/新增/修改之类的。 可以手动转换为对比节点(compareTree)也可以通过parse方法自动转换,自动转换可以手动配置转换结构。
三个版本数据对比
- 三个版本
- 当前版本
- 基础版本
其他版本
- 差异获取
- 当前版本与基础版本对比得到一个差异状态树(currentDiff)。
- 其他版本与基础版本对比得到一个差异状态树(otherDiff)。
currentDiff 与 otherDiff 对比得到最终的一个差异树。
注意:只有三个版本对比才会出现冲突状态。冲突是指当前版本与其他版本都修改了同一个属性则会导致冲突。
数据对比的结构
// 必须要的属性
export type CompareDataAttr = { id?: number, name?: string }
export type CompareData = CompareDataAttr & Obj
export interface CompareTree<T extends CompareDataAttr = CompareData> extends Obj {
// 树节点id
id: number
// 树节点名称 也可以通过配置更改 config
name?: string
// 需要对比的数据
compareData: Partial<T> & CompareDataAttr
// 源数据
target?: T
// 状态
status: AttrCompareStatus
// 当前节点的位置更换信息
changeInfo?: ChangeCompareInfo
// 子节点的位置跟换信息
childrenChangeInfo?: ChildrenChangeCompareInfo
// 子节点
children: CompareTree<T>[]
// 父节点
parent?: CompareTree<T>
// 当前节点id与另一个对比数id的映射
mappingId?: number
// 是否对比更换位置状态
diffChange?: boolean
}
methods
createCompareNode: 创建一个对比节点
- createCompareNode (data: CreateCompareTreeProps, parent?: CompareTree, isClone = false): CompareTree
- @param data 原始数据。
- @param parent 父节点。
- @param isClone 是否为clone节点,clone节点不会触发 beforeCreateCompareNode 钩子
- @returns 返回创建成功后的节点
import { createCompareNode } from '@chendf/data-compare'
const data = {
id: 1,
name: '名称'
}
const compareTree = createCompareNode({compareData: data, target: data})
// 返回一个树节点
speedCreateCompareNode: 快速创建一个对比节点
- speedCreateCompareNode (data: T, parent?: CompareTree): CompareTree
- @param data 原始数据
- @param parent 父节点
- @returns 返回创建成功后的节点
import { speedCreateCompareNode } from '@chendf/data-compare'
const data = {
id: 1,
name: '名称'
}
const compareTree = speedCreateCompareNode(data)
// 返回一个树节点
diffCompareTree: 对比两个对比树节点之间的差异 (两个重载)
- diffCompareTree(origin: CompareTree[], target: CompareTree[], parent?: CompareTree): CompareTree[]
- diffCompareTree(origin: CompareTree, target: CompareTree, parent?: CompareTree): CompareTree[]
- @param origin 原始数据,该方法是会修改原始数据的
- @param target 对比的数据
- @param parent 父节点数据
- @returns 对比后的数据
import { speedCreateCompareNode, diffCompareTree } from '@chendf/data-compare'
const data = {
id: 1,
name: '名称'
}
const compareTree1 = speedCreateCompareNode(data)
const data2 = {
id: 1,
name: '名称2'
}
const compareTree2 = speedCreateCompareNode(data2)
diffCompareTree(compareTree1, compareTree2)
// return
[
{
id: 1,
name: "名称",
compareData: {
id: 1,
name: "名称"
},
target: {
id: 1,
name: "名称"
},
status: {
type: "update",
path: "",
attrStatus: {
name: {
type: "update",
path: "name",
oldValue: "名称2"
}
}
},
children: []
}
]
diffStatus: 对比两个差异树节点状态,并且设置冲突状态。如果两边都有修改那么当前节点就为冲突状态,也可通过钩子手动调整
- diffStatus(current: CompareTree[], online: CompareTree[], currentParent?: CompareTree, onlineParent?: CompareTree): void
- diffStatus(current: CompareTree, online: CompareTree, currentParent?: CompareTree, onlineParent?: CompareTree): void
- @param current 当前版本数据
- @param online 线上版本数据
- @param currentParent 当前版本父节点
- @param onlineParent 线上版本父节点
import { speedCreateCompareNode, diffCompareTree, diffStatus } from '@chendf/data-compare'
const current = {
id: 1,
name: '名称1',
test: 1,
update: 1
}
const currentTree = speedCreateCompareNode(current)
const base = {
id: 1,
name: '名称',
test: 1,
update: 2
}
const baseTree = speedCreateCompareNode(base)
const online = {
id: 1,
name: '名称2',
test: 1,
update: 2
}
const onlineTree = speedCreateCompareNode(online)
const currentBase = diffCompareTree(currentTree, baseTree)
const onlineBase = diffCompareTree(onlineTree, baseTree)
// 对比状态
diffStatus(currentBase, onlineBase)
// currentBase
[
{
"id": 1,
"name": "名称1",
"compareData": {
"id": 1,
"name": "名称1",
"test": 1,
"update": 1
},
"target": {
"id": 1,
"name": "名称1",
"test": 1,
"update": 1
},
"status": {
"type": "conflict",
"path": "",
"attrStatus": {
"name": {
"type": "conflict",
"path": "name",
"oldValue": "名称"
},
"update": {
"type": "update",
"path": "update",
"oldValue": 2
}
}
},
"children": [],
"mappingId": 3
}
]
// onlineBase
[
{
"id": 3,
"name": "名称2",
"compareData": {
"id": 1,
"name": "名称2",
"test": 1,
"update": 2
},
"target": {
"id": 1,
"name": "名称2",
"test": 1,
"update": 2
},
"status": {
"type": "conflict",
"path": "",
"attrStatus": {
"name": {
"type": "conflict",
"path": "name",
"oldValue": "名称"
}
}
},
"children": [],
"mappingId": 1
}
]
speedDiffStatus: 快速对比三个数据之间的差异
- speedDiffStatus (current: T, online: T, base: T): SpeedDiffStatusType
- @param current 当前版本
- @param online 线上版本
- @param base 基础版本
import { speedDiffStatus } from '@chendf/data-compare'
const current = {
id: 1,
name: '名称1',
test: 1,
update: 1
}
const base = {
id: 1,
name: '名称',
test: 1,
update: 2
}
const online = {
id: 1,
name: '名称2',
test: 1,
update: 2
}
this.speedDiffStatus(current, online, base)
// 结果与 diffStatus 结果一致
diffAttr: 对比两个对象之间的差异,能展示出每个对象节点的差异,并且有存储对应的路径与旧值
- diffAttr (origin: unknown, target: unknown, pathStacks: string[] = []): AttrCompareStatus
- @param origin 当前版本数据。
- @param target 其他版本数据。
- @param pathStacks 可选参数,为当前对比的节点的key路径。
import { diffAttr } from '@chendf/data-compare'
const diffResult = diffAttr({ a: 2, b: 2, d: 1 }, { a: 1, b: 2, c: 3 })
// 返回结果
{
type: "update",
path: "",
attrStatus: {
a: {
type: "update",
path: "a",
oldValue: 1
},
d: {
type: "create",
path: "d"
},
c: {
type: "delete",
path: "c"
}
}
}
shallowDiffAttr: 对比两个对象之间的差异,返回对象的第一层结果差异,如果无差异则返回 undefined
,并且有存储对应的路径与旧值
- shallowDiffAttr (origin: unknown, target: unknown, pathStacks: string[] = []): UndefinedAble
- @param origin 当前版本数据。
- @param target 其他版本数据。
- @param pathStacks 可选参数,为当前对比的节点的key路径。
import { shallowDiffAttr } from '@chendf/data-compare'
const diffResult = shallowDiffAttr({ a: 2, b: 2, d: 1 }, { a: 1, b: 2, c: 3 })
// 返回结果
{
"a": {
"type": "update",
"newValue": 2,
"oldValue": 1
},
"d": {
"type": "create",
"newValue": 1,
"oldValue": undefined
},
"c": {
"type": "delete",
"newValue": undefined,
"oldValue": 3
}
}
updateConfig: 修改配置
- updateConfig(config: Partial)
- config:
- childrenKey?: string // 解析为子节点的key
- someKey?: string // 对比的key
- nameKey?: string // 展示的name
parse: 将数据自动解析为对比节点 (如果想要自动解析按照自己数据格式解析,可以修改配置信息)
- parse(data: T, parent?: CompareTree): CompareTree
- parse(data: T[], parent?: CompareTree): CompareTree[]
import { parse } from '@chendf/data-compare'
const data = {
id: 1,
name: '名称2',
test: 1,
update: 2
}
const compareTree = parse(data) // 结果与直接调用 speedCreateCompareNode 一致 (不修改配置的情况下)
钩子函数 所有的钩子都存储在 cycle 对象上
钩子函数是指在对比期间调用的一些方法,可以让你定制化对比。
beforeCreateCompareNode: 创建对比节点之前调用。
- callback:
- @param compareTree 根据当前源创建的节点数据
import { cycle } from '@chendf/data-compare'
cycle.beforeCreateCompareNode(compareTree => {
// 如果想要对数据进行修改,只需要处理data即可
compareTree.name = 'update' // example
})
beforeCompare: 在diffCompareTree每个节点之前调用
- callback(origin: CompareTree[], target: CompareTree[], parent?: CompareTree)
- @param origin 当前数据
- @param target 对比的数据
- @param parent 父节点
afterCompare: 在diffCompareTree每个节点之后调用
- callback(origin: CompareTree[], target: CompareTree[], parent?: CompareTree)
- @param origin 当前数据
- @param target 对比的数据
- @param parent 父节点
beforeDiffStatus: 在diffStatus当前父节点下的每个直属子节点之前调用
- callback(current: CompareTree[], online: CompareTree[], currentParent?: CompareTree, onlineParent?: CompareTree)
- @param current 当前数据
- @param online 对比的数据
- @param currentParent current父节点
- @param onlineParent online父节点
afterDiffStatus: 在diffStatus当前父节点下的每个直属子节点之后调用
- callback(current: CompareTree[], online: CompareTree[], currentParent?: CompareTree, onlineParent?: CompareTree)
- @param current 当前数据
- @param online 对比的数据
- @param currentParent current父节点
- @param onlineParent online父节点
afterCompareStatus: 在diffStatus中每个节点对比之后会调用。包括克隆的节点也会调用改钩子
- callback(current: CompareTree, online: CompareTree)
- @param current 当前数据
- @param online 对比的数据
beforeCloneCompareTree: 对比中有些数据是被删除的,为了维护另一边对应的数据结构,需要手动克隆一份节点数据,改钩子在克隆之前会调用,clone之后会调用 afterCompareStatus
- callback(cloneTree: CompareTree, statusType: CompareStatusEnum, parent?: CompareTree, isOnline?: boolean)
- @param cloneTree 需要克隆的数据
- @param statusType clone的状态
- @param parent 当前克隆节点的父节点
- @param isOnline 克隆的是当前数据还是对比数据, true为克隆的对比数据
parse钩子 parse钩子不会解析每个节点的时候都调用,如果需要解析每个节点都做处理,请使用 beforeCreateCompareNode
beforeParse: 解析节点之前调用
- callback 参数为 parse 方法调用的参数
afterParse: 解析节点之后调用
- callback(data: T | T[], newNode: CompareTree, parent?: CompareTree)
- @param data 原始数据
- @param newNode 生成的节点数据
- _@param parent 父
全局钩子函数
注意:全局钩子函数有且只能有一个
useBeforeSameValue
: 在对比两个值是否相等之前掉用,可以修改两个值是否相等。返回true
代表两个值相等
,返回false
代表两个值不相等
。- callback(callback: (originSameValue: ISameValue, newSameValue: ISameValue, originValue: any, newValue: any)
ISameValue
: { key: string / 当前对比的 key */ , value: any / 当前对比的 value */ }- @param originSameValue 旧数据
- @param newSameValue 新数据
- @param originValue 旧原始数据 (即 diff 的 origin)
- @param newValue 新原始数据 (即 diff 的 target)
- callback(callback: (originSameValue: ISameValue, newSameValue: ISameValue, originValue: any, newValue: any)