JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 126
  • Score
    100M100P100Q32588F
  • License BSD-3-Clause

Lightweight JSON Patch (RFC 6902) utilities for Node.js and the browser

Package Exports

  • nano-rfc6902
  • nano-rfc6902/isSafeApply

Readme

nano-rfc6902

Lightweight JSON Patch (RFC 6902) utilities for Node.js and the browser.

npm version npm downloads CI license zero deps types bundle size node version

Highlights:

  • Zero dependencies

  • Tiny footprint (≤ 2 kB min+gz)

  • Fast diff/patch

  • ESM + CJS + types

  • Works in Node.js and modern browsers

  • Generate patches: createPatch(oldValue, newValue)

  • Apply patches in-place: applyPatch(target, patch)

Installation

npm install nano-rfc6902

Quick start

Node.js (ESM)

import { createPatch, applyPatch } from "nano-rfc6902";

const before = { name: "Ada", skills: ["math"] };
const after = { name: "Ada Lovelace", skills: ["math", "programming"] };

// 1) Create a JSON Patch (RFC 6902 operations)
const patch = createPatch(before, after);
// Example patch (shape will depend on diff):
// [
//   { op: 'replace', path: '/name', value: 'Ada Lovelace' },
//   { op: 'add',     path: '/skills/1', value: 'programming' }
// ]

// 2) Apply the patch (mutates the target in-place)
applyPatch(before, patch);

console.log(before); // -> { name: 'Ada Lovelace', skills: ['math', 'programming'] }

Node.js (CommonJS)

const { createPatch, applyPatch } = require("nano-rfc6902");

const a = { count: 1 };
const b = { count: 2 };

const patch = createPatch(a, b);
applyPatch(a, patch);

console.log(a); // -> { count: 2 }

Browser

With a bundler (Vite, Webpack, etc.), import from the package name:

<script type="module">
  import { createPatch, applyPatch } from "nano-rfc6902";

  const oldState = { items: ["a"] };
  const newState = { items: ["a", "b"] };

  const patch = createPatch(oldState, newState);
  applyPatch(oldState, patch);

  console.log(oldState); // -> { items: ['a', 'b'] }
</script>

Without a bundler, you can use a CDN that serves ESM:

<script type="module">
  import {
    createPatch,
    applyPatch,
  } from "https://cdn.jsdelivr.net/npm/nano-rfc6902/+esm";

  const src = { a: 1 };
  const dst = { a: 1, b: 2 };

  const patch = createPatch(src, dst);
  applyPatch(src, patch);

  console.log(patch); // e.g., [{ op: 'add', path: '/b', value: 2 }]
</script>

API

createPatch(oldValue, newValue) => Operation[]

Computes a minimal set of RFC 6902 operations to transform oldValue into newValue.

  • Diffs primitives, objects, and arrays.
  • Arrays use an LCS-based strategy to produce intuitive insert/remove/replace operations and preserve nested diffs when elements are equal by deep comparison.

applyPatch(target, patch) => void

Applies an RFC 6902 patch to target in-place.

  • Supports add, remove, replace, move, copy, and test.
  • Uses JSON Pointer (RFC 6901) for path and from fields (e.g., /a/b/0).
  • Throws if paths are invalid or test fails.

Utils: isSafeApply(patch) => boolean

A small utility exported as a separate entry that validates whether a patch only targets object keys (and never array indices or the special - append). Returns true if the patch is safe to apply without mutating array positions. Implementation: TypeScript.isSafeApply()

Import

  • ESM:
    import { isSafeApply } from "nano-rfc6902/isSafeApply";
  • CommonJS:
    const { isSafeApply } = require("nano-rfc6902/isSafeApply");

Safe examples (true)

import { isSafeApply } from "nano-rfc6902/isSafeApply";

const patch = [
  { op: "add", path: "/user/name", value: "Ada" },
  { op: "replace", path: "/meta/title", value: "Dr." },
  { op: "test", path: "/count", value: 1 },
];
isSafeApply(patch); // true

Unsafe examples (false)

import { isSafeApply } from "nano-rfc6902/isSafeApply";

// Targets array index
isSafeApply([{ op: "add", path: "/items/0", value: "a" }]); // false

// Appends to array end
isSafeApply([{ op: "add", path: "/items/-", value: "a" }]); // false

// move/copy touching arrays (either from or path)
isSafeApply([{ op: "move", from: "/items/0", path: "/items/1" }]); // false
isSafeApply([{ op: "copy", from: "/a/0", path: "/b/0" }]); // false

Notes

  • For move and copy, both from and path must be object-key paths (no array indices or -).
  • Empty patches are considered safe.

Types (TypeScript)

This package ships first-class types. Core shapes mirror RFC 6902:

type JSONValue =
  | string
  | number
  | boolean
  | null
  | undefined
  | JSONValue[]
  | { [key: string]: JSONValue };

type Operation =
  | { op: "add"; path: string; value: JSONValue }
  | { op: "remove"; path: string }
  | { op: "replace"; path: string; value: JSONValue }
  | { op: "move"; from: string; path: string }
  | { op: "copy"; from: string; path: string }
  | { op: "test"; path: string; value: JSONValue };

Notes:

  • JSON Pointer escaping follows RFC 6901: ~ -> ~0, / -> ~1.
  • applyPatch mutates the target you pass in.
  • undefined is included in JSONValue for ergonomic diffs in JS/TS; be aware that literal JSON does not have undefined.

Development

Prerequisites

  • Node.js >= 20.0.0 (LTS)
  • npm or pnpm

Install dependencies

npm install

Build

npm run build

Outputs:

  • dist/index.js — ES module
  • dist/index.cjs — CommonJS
  • dist/index.d.ts — TypeScript declarations

Type checking

npm run type-check

Tests

npm test

Features

  • Zero dependencies
  • Tiny footprint: ≤ 2 kB min+gz (size-limit target)
  • Fast and efficient diff/patch
  • JSON Patch (RFC 6902) create/apply
  • Small API surface
  • TypeScript types included
  • Works in Node.js and modern browsers
  • ESM and CJS builds

License

BSD-3-Clause