npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chendf/data-compare

v1.4.5

Published

data-compare是一个对比数据之间差异的一个轻量级库,类似于简化版本的git对比。也可以单纯用来对比两个数据之间的差异。

Readme

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)