Skip to content

wsafight/diff-helper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

diff-helper

NPM Version License

Read this in other languages: English

基于实际业务场景的轻量 diff 辅助库。提供对象与数组的结构化比对、主键列表 diff、排序感知以及通用递归 diff。

开发历程可以参考博客 手写一个业务数据比对库

特性

  • 针对业务场景的 diff,而非通用全量 patch
  • simpleObjDiff / isSimpleObjChange —— 对象浅层 diff 与快速变更判定
  • simpleListDiff —— 基于主键 key 的数组 diff,内部使用 Map 索引,查找 O(1)
  • 可选 sortName,追踪位置变化
  • commonDiff —— 任意对象/数组递归 diff,保留层级结构
  • 零运行时依赖,ESM + CJS 双产物

安装

npm install diff-helper
#
yarn add diff-helper
#
bun add diff-helper

API 速览

函数 用途
simpleObjDiff 对象浅层 diff,返回差异字段
isSimpleObjChange 判断两个对象是否发生变化(不返回 diff 结果)
simpleListDiff 按主键 diff 数组,返回增/删/改
commonDiff 通用递归 diff,保留嵌套结构

simpleObjDiff

对两个对象做浅层 diff,返回包含差异字段的对象。可传入 diffFun 自定义单字段比对逻辑。

参数

参数 说明 类型 默认值
newVal 新对象 Record<string, any> -
oldVal 老对象 Record<string, any> -
options.empty 旧对象有、新对象无时的占位值 null | '' null
options.diffFun 单字段比对函数,返回 null/undefined 时走默认比对 ({ key, newPropVal, oldPropVal }) => any -
options.needCopy 是否对变更字段做 JSON 深拷贝 boolean false

例子

import { simpleObjDiff } from 'diff-helper';

simpleObjDiff({
  newVal: { b: 1, c: 12, e: '123', f: ['2131', 231, '1111'] },
  oldVal: { b: 123, a: 123213, e: '123', f: ['2131', 231, '1111'] },
});
// => { b: 1, c: 12, a: null }

simpleObjDiff({
  newVal: { b: 1, c: 12 },
  oldVal: { b: 123, a: 123213 },
  options: { empty: '' },
});
// => { b: 1, c: 12, a: '' }

simpleObjDiff({
  newVal: { a: [12, 3, 4], b: 11 },
  oldVal: { a: [1, 2, 3], c: 22 },
  options: {
    diffFun: ({ key, newPropVal, oldPropVal }) => {
      if (key === 'a') {
        return newPropVal.filter((item: any) => oldPropVal.includes(item));
      }
      return null; // 走默认 JSON 比对
    },
  },
});
// => { a: [3], b: 11, c: null }

isSimpleObjChange

只判断两个对象是否有变化,不构造 diff 结果。当仅需判断是否需要触发后续流程(如发请求、重渲染)时更轻量。

import { isSimpleObjChange } from 'diff-helper';

isSimpleObjChange({
  newVal: { a: 1, b: { c: 2 } },
  oldVal: { a: 1, b: { c: 2 } },
});
// => false

isSimpleObjChange({
  newVal: { a: 1 },
  oldVal: { a: 1, b: 2 },
});
// => true (key 数不同)

simpleListDiff

对带主键的数组做 diff,返回 addedLines / deletedLines / modifiedLines。传入 sortName 时额外返回 noChangeLines 并记录位置。

参数

参数 说明 类型 默认值
newVal 新数组 any[] -
oldVal 老数组 any[] -
options.key 行主键字段名 string 'id'
options.getChangedItem 自定义变更判定;返回 null 表示未变更 ({ newLine, oldLine }) => any 内部用 simpleObjDiff
options.sortName 传入后额外输出 noChangeLines 并记录 index + 1 string ''

例子

import { simpleListDiff } from 'diff-helper';

// 不传 getChangedItem,内部用 simpleObjDiff
simpleListDiff({
  newVal: [{ id: 1, cc: 'bbc' }, { bb: '123' }],
  oldVal: [{ id: 1, cc: 'bb' }, { id: 2, cc: 'bdf' }],
  options: { key: 'id' },
});
// => {
//   addedLines:    [{ bb: '123' }],
//   deletedLines:  [{ id: 2 }],
//   modifiedLines: [{ id: 1, cc: 'bbc' }],
// }

// sortName 模式:追踪未变动但位置改变的行
simpleListDiff({
  newVal: [
    { id: 2, cc: 'bdf' },
    { id: 3, bb: '333' },
    { id: 1, cc: 'bb' },
  ],
  oldVal: [
    { id: 1, cc: 'bb' },
    { id: 3, bb: '333' },
    { id: 2, cc: 'bdf' },
  ],
  options: { key: 'id', sortName: 'sortIndex' },
});
// => {
//   addedLines:    [],
//   deletedLines:  [],
//   modifiedLines: [],
//   noChangeLines: [
//     { id: 2, sortIndex: 1 },
//     { id: 1, sortIndex: 3 },
//   ],
// }

// 新增 + 未变动行同时带 sortIndex
simpleListDiff({
  newVal: [{ id: 2, cc: 'bbc' }, { id: 1, cc: 'bb' }],
  oldVal: [{ id: 1, cc: 'bb' }],
  options: { key: 'id', sortName: 'sortIndex' },
});
// => {
//   addedLines:    [{ id: 2, cc: 'bbc', sortIndex: 1 }],
//   deletedLines:  [],
//   modifiedLines: [],
//   noChangeLines: [{ id: 1, sortIndex: 2 }],
// }

commonDiff

对任意嵌套对象/数组做递归 diff。结果保留层级结构,每层带 type: 'obj' | 'array'。完全无差异时返回 null

参数

参数 说明 类型 默认值
newVal 新值 any -
oldVal 老值 any -
empty 旧端存在、新端缺失时的占位 null | '' | undefined null

行为要点:

  • undefined 统一视作 null
  • DatevalueOf() 比较
  • 嵌套层无差异时不会出现在结果中

例子

import { commonDiff } from 'diff-helper';

commonDiff(
  { a: 1, b: { x: 2, y: 3 }, d: 4 },
  { a: 1, b: { x: 2, y: 9 }, c: 5 }
);
// => { b: { y: 3, type: 'obj' }, d: 4, c: null, type: 'obj' }

commonDiff([1, 2, 3], [1, 9, 3]);
// => { '1': 2, type: 'array' }

commonDiff({ a: 1 }, { a: 1 });
// => null

commonDiff(new Date('2024-01-01'), new Date('2024-01-01'));
// => null

开发

bun install        # 装依赖
bun test           # 跑测试(78 用例)
bun run typecheck  # tsc 类型检查
bun run check      # biome 格式化 + lint
bun run build      # 产出 dist/(ESM + CJS + d.ts)

Changelog

  • 2.0.0 simpleListDiff 查找复杂度由 O(n²) 降为 O(n);新增 commonDiff 通用递归比对;补齐 isSimpleObjChange 文档;工具链迁移至 Bun + Biome + TypeScript 6;测试用例扩充至 78 个
  • 1.0.1 新增 commonDiff 通用递归比对;修复 commonDiff 参数顺序、Date 判定、simpleObjDiff 深拷贝等问题
  • 1.0.0 移除 simpleListDiffWithSort,清理 simpleListDiff 中不必要的参数
  • 0.0.5simpleListDiffsimpleListDiffWithSortoptions.getChangedItem 提供可用默认项
  • 0.0.4 新增 simpleListDiffsimpleListDiffWithSort 及测试
  • 0.0.3 修复 simpleObjDiff diffFun 返回 false 的问题,调整参数结构,新增 isSimpleObjChange
  • 0.0.2 基础可用,支持 simpleObjDiffsimpleListDiff

License

MIT

About

Comparison auxiliary library based on actual business

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors