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

@json-visual-diff/core

v0.0.1

Published

核心差异算法引擎,提供高性能的 JSON 对象比较功能,支持智能数组对比、扩展类型和循环引用检测

Readme

@json-visual-diff/core

一个强大且灵活的 JSON diff 算法库,用于计算两个 JSON 对象之间的差异并生成标准化的 diff 结果。

English Documentation

特性

  • 🚀 纯算法实现: 平台无关的核心库,可在任何 JavaScript 环境中运行
  • 🔍 智能数组 Diff: 使用 LCS(最长公共子序列)算法进行智能数组比较
  • 🎯 扩展类型支持: 处理 Function、Date、RegExp、Symbol 等非标准 JSON 类型
  • 🔄 循环引用检测: 安全处理循环引用,避免无限循环
  • 📊 标准化输出: 生成一致的 DiffResult 格式,便于使用
  • 🎨 渲染器无关: 核心算法与渲染逻辑完全解耦
  • 💪 TypeScript 优先: 完整的类型定义,提供出色的 IDE 支持
  • 性能优化: 可配置的深度限制和高效算法

安装

npm install @json-visual-diff/core
# 或
pnpm add @json-visual-diff/core
# 或
yarn add @json-visual-diff/core

快速开始

import { diff } from '@json-visual-diff/core';

const oldObj = {
  name: 'John',
  age: 25,
  hobbies: ['reading', 'gaming']
};

const newObj = {
  name: 'John',
  age: 26,
  hobbies: ['reading', 'coding', 'gaming'],
  email: '[email protected]'
};

const result = diff(oldObj, newObj);

console.log(result);
// {
//   root: { ... },
//   stats: {
//     added: 1,
//     deleted: 0,
//     modified: 2,
//     unchanged: 1
//   }
// }

API 文档

diff(oldValue, newValue, options?)

计算两个值之间的差异并返回 DiffResult。

参数:

  • oldValue: any - 原始值
  • newValue: any - 要比较的新值
  • options?: DiffOptions - 可选配置

返回值: DiffResult

示例:

import { diff } from '@json-visual-diff/core';

const result = diff(
  { a: 1, b: 2 },
  { a: 1, b: 3, c: 4 },
  {
    maxDepth: 10,
    arrayDiffMode: 'lcs',
    detectCircular: true
  }
);

DiffEngine

执行比较的核心 diff 引擎类。

构造函数:

import { DiffEngine } from '@json-visual-diff/core';

const engine = new DiffEngine({
  maxDepth: 10,
  ignoreKeys: ['_id', 'timestamp'],
  arrayDiffMode: 'lcs',
  detectCircular: true
});

const result = engine.compute(oldValue, newValue);

方法:

  • compute(oldValue, newValue): DiffResult - 计算完整的 diff 结果(包含统计信息)
  • diff(oldValue, newValue, path?): DiffNode - 计算特定路径的 diff

TypeNormalizer

用于规范化非标准 JSON 类型的工具类。

静态方法:

import { TypeNormalizer } from '@json-visual-diff/core';

// 获取值的类型
const type = TypeNormalizer.getValueType(value);

// 将函数规范化为可比较的字符串
const fnStr = TypeNormalizer.normalizeFunction(myFunction);

// 将 Date 规范化为时间戳
const timestamp = TypeNormalizer.normalizeDate(new Date());

// 将 RegExp 规范化为字符串
const regexpStr = TypeNormalizer.normalizeRegExp(/test/gi);

// 将值序列化为可显示的字符串
const str = TypeNormalizer.serialize(value, type);

LCSArrayDiff

用于智能数组 diff 的 LCS(最长公共子序列)算法实现。

静态方法:

import { LCSArrayDiff } from '@json-visual-diff/core';

// 计算两个数组的 LCS
const dp = LCSArrayDiff.computeLCS(arr1, arr2);

// 获取 diff 操作序列
const ops = LCSArrayDiff.diff(arr1, arr2);

// 深度相等性检查
const isEqual = LCSArrayDiff.isEqual(value1, value2);

DiffResultBuilder

用于构建和操作 DiffNode 结构的辅助类。

静态方法:

import { DiffResultBuilder } from '@json-visual-diff/core';

// 创建不同类型的节点
const addedNode = DiffResultBuilder.createAddedNode(path, valueType, newValue);
const deletedNode = DiffResultBuilder.createDeletedNode(path, valueType, oldValue);
const modifiedNode = DiffResultBuilder.createModifiedNode(path, valueType, oldValue, newValue);
const unchangedNode = DiffResultBuilder.createUnchangedNode(path, valueType, value);

// 构建 JSON Path
const jsonPath = DiffResultBuilder.buildJsonPath(['user', 'address', 'city']);
// 返回: "$.user.address.city"

// 计算统计信息
const stats = DiffResultBuilder.computeStats(rootNode);

// 验证节点结构
const isValid = DiffResultBuilder.validateNode(node);

// 根据路径查找节点
const node = DiffResultBuilder.findNodeByPath(root, ['user', 'name']);

类型定义

DiffType

enum DiffType {
  ADDED = 'added',       // 属性被添加
  DELETED = 'deleted',   // 属性被删除
  MODIFIED = 'modified', // 属性被修改
  UNCHANGED = 'unchanged' // 属性未改变
}

ValueType

enum ValueType {
  PRIMITIVE = 'primitive', // string, number, boolean
  OBJECT = 'object',       // 普通对象
  ARRAY = 'array',         // 数组
  FUNCTION = 'function',   // 函数
  DATE = 'date',           // Date 对象
  REGEXP = 'regexp',       // RegExp 对象
  UNDEFINED = 'undefined', // undefined
  NULL = 'null',           // null
  SYMBOL = 'symbol'        // Symbol
}

DiffNode

interface DiffNode {
  type: DiffType;           // 差异类型
  path: string[];           // JSON Path(数组形式)
  valueType: ValueType;     // 值的类型
  oldValue?: any;           // 旧值(删除/修改时)
  newValue?: any;           // 新值(添加/修改时)
  children?: DiffNode[];    // 子节点(对象/数组)
}

DiffResult

interface DiffResult {
  root: DiffNode;           // 根 diff 节点
  stats: {                  // 统计信息
    added: number;
    deleted: number;
    modified: number;
    unchanged: number;
  };
}

DiffOptions

interface DiffOptions {
  maxDepth?: number;        // 最大比较深度(默认: Infinity)
  ignoreKeys?: string[];    // 要忽略的键(默认: [])
  arrayDiffMode?: 'lcs' | 'position'; // 数组比较模式(默认: 'lcs')
  detectCircular?: boolean; // 检测循环引用(默认: true)
}

高级用法

处理扩展类型

import { diff } from '@json-visual-diff/core';

const oldObj = {
  fn: function add(a, b) { return a + b; },
  date: new Date('2024-01-01'),
  regex: /test/gi,
  sym: Symbol('test')
};

const newObj = {
  fn: function add(a, b) { return a + b; },
  date: new Date('2024-01-02'),
  regex: /test/i,
  sym: Symbol('test')
};

const result = diff(oldObj, newObj);
// 正确识别 date 和 regex 被修改

循环引用处理

import { diff } from '@json-visual-diff/core';

const obj1 = { name: 'circular' };
obj1.self = obj1;

const obj2 = { name: 'circular' };
obj2.self = obj2;

const result = diff(obj1, obj2, { detectCircular: true });
// 安全处理循环引用,不会导致无限循环

自定义深度限制

import { diff } from '@json-visual-diff/core';

const deepObj1 = {
  level1: {
    level2: {
      level3: {
        level4: { value: 'deep' }
      }
    }
  }
};

const deepObj2 = {
  level1: {
    level2: {
      level3: {
        level4: { value: 'deeper' }
      }
    }
  }
};

const result = diff(deepObj1, deepObj2, { maxDepth: 3 });
// 在第 3 层停止比较

数组 Diff 模式

import { diff } from '@json-visual-diff/core';

const arr1 = [1, 2, 3, 4];
const arr2 = [1, 3, 4, 5];

// LCS 模式(智能 diff)
const lcsResult = diff(arr1, arr2, { arrayDiffMode: 'lcs' });
// 识别出 2 被删除,5 被添加

// 位置模式(逐个索引比较)
const posResult = diff(arr1, arr2, { arrayDiffMode: 'position' });
// 比较 arr1[0] 与 arr2[0],arr1[1] 与 arr2[1],等等

忽略特定键

import { diff } from '@json-visual-diff/core';

const obj1 = {
  id: '123',
  timestamp: 1234567890,
  data: { value: 'old' }
};

const obj2 = {
  id: '456',
  timestamp: 9876543210,
  data: { value: 'new' }
};

const result = diff(obj1, obj2, {
  ignoreKeys: ['id', 'timestamp']
});
// 只比较 'data' 字段

与渲染器集成

这个核心库设计为可与可插拔的渲染器配合使用。标准化的 DiffResult 格式可以被任何渲染器实现使用。

import { diff } from '@json-visual-diff/core';
import { DOMRenderer } from '@json-visual-diff/dom-renderer';

const result = diff(oldObj, newObj);
const renderer = new DOMRenderer();
const htmlElement = renderer.render(result);

document.body.appendChild(htmlElement);

性能考虑

  • 大型对象: 使用 maxDepth 选项限制比较深度
  • 大型数组: LCS 算法的时间复杂度为 O(m*n),对于非常大的数组考虑使用 arrayDiffMode: 'position'
  • 循环引用: 启用 detectCircular 以防止无限循环(默认启用)

许可证

MIT

相关包

贡献

欢迎贡献!请随时提交 Pull Request。

支持

如果您遇到任何问题或有疑问,请在我们的 GitHub 仓库 上提交 issue。