Skip to content

feat: Add comprehensive tests for generateJSONPatch #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
module.exports = {
parser: '@typescript-eslint/parser',
env: {
node: true,
jest: true,
parser: '@typescript-eslint/parser',
env: {
node: true,
jest: true,
},
plugins: ['@typescript-eslint', 'prettier'],
extends: ['eslint:recommended', 'plugin:prettier/recommended'],
rules: {
'no-unused-vars': 'off',
'no-prototype-builtins': 'off',
'@typescript-eslint/no-unused-vars': ['error', { 'argsIgnorePattern': '^_' , 'varsIgnorePattern': '^_' }],
},
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
ecmaFeatures: {
modules: true,
},
plugins: ['@typescript-eslint', 'prettier'],
extends: ['eslint:recommended', 'plugin:prettier/recommended'],
rules: {
'no-unused-vars': 'off',
'no-prototype-builtins': 'off',
'@typescript-eslint/no-unused-vars': 'error',
},
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
ecmaFeatures: {
modules: true,
},
},
};
},
};
12 changes: 3 additions & 9 deletions .nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@
"functions": 95,
"lines": 95,
"check-coverage": true,
"exclude": [
"src/*.spec.ts"
],
"reporter": [
"text-summary",
"lcov",
"clover"
]
}
"exclude": ["src/*.spec.ts"],
"reporter": ["text-summary", "lcov", "clover"]
}
142 changes: 84 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
# generate-json-patch

Create [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902/) compliant JSON Patch objects based on two given [JSON](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/) objects with a configurable interface.
Create [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902/) compliant JSON Patch objects based on two given [JSON](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/) objects with a configurable interface.

[![Version](https://img.shields.io/npm/v/generate-json-patch.svg)](https://npmjs.org/package/generate-json-patch)
[![Downloads/week](https://img.shields.io/npm/dw/generate-json-patch.svg)](https://npmjs.org/package/generate-json-patch)
[![Size](https://img.shields.io/bundlephobia/min/generate-json-patch.svg)](https://npmjs.org/package/generate-json-patch)
[![Tests](https://github.com/marcolink/generate-json-patch/workflows/CI%20Tests/badge.svg?branch=main)](https://github.com/marcolink/generate-json-patch/actions/workflows/test.yml)
[![License](https://img.shields.io/npm/l/generate-json-patch.svg)](https://github.com/marcoxlink/generate-json-patch/blob/main/package.json)
[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)

# TL;DR
- Can diff any two [JSON](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/) compliant objects - returns differences as [JSON Patch](http://jsonpatch.com/).

- Can diff any two [JSON](https://www.ecma-international.org/publications-and-standards/standards/ecma-404/) compliant objects - returns differences as [JSON Patch](http://jsonpatch.com/).
- Elegant array diffing by providing an `objectHash` to match array elements
- Ignore specific keys by providing a `propertyFilter`
- :paw_prints: ***Is it small?*** Zero dependencies - it's ~**3 KB** (minified).
- :crystal_ball: ***Is it fast?*** I haven't done any performance comparison yet.
- :hatched_chick: ***Is it stable?*** Test coverage is high, but it's still in its early days - bugs are expected.
- :paw_prints: **_Is it small?_** Zero dependencies - it's ~**3 KB** (minified).
- :crystal_ball: **_Is it fast?_** I haven't done any performance comparison yet.
- :hatched_chick: **_Is it stable?_** Test coverage is high, but it's still in its early days - bugs are expected.
- The interface is inspired by [jsondiffpatch](https://github.com/benjamine/jsondiffpatch)
- **100%** Typescript

# Installation
Works on node and browser environments.
# Installation

Works on node and browser environments.

```bash
npm install generate-json-patch
```
Expand All @@ -29,89 +33,111 @@ npm install generate-json-patch
```typescript
import { generateJSONPatch } from 'generate-json-patch';

const before = { manufacturer: "Ford", type: "Granada", year: 1972 };
const after = { manufacturer: "Ford", type: "Granada", year: 1974 };
const before = { manufacturer: 'Ford', type: 'Granada', year: 1972 };
const after = { manufacturer: 'Ford', type: 'Granada', year: 1974 };

const patch = generateJSONPatch(before, after);

console.log(patch) // => [{op: 'replace', path: '/year', value: 1974}]
console.log(patch); // => [{op: 'replace', path: '/year', value: 1974}]
```

## Configuration

```typescript
import { generateJSONPatch, JsonPatchConfig, JsonValue, ObjectHashContext } from 'generate-json-patch';

generateJSONPatch({/*...*/}, {/*...*/}, {
import {
generateJSONPatch,
JsonPatchConfig,
JsonValue,
ObjectHashContext,
} from 'generate-json-patch';

generateJSONPatch(
{
/*...*/
},
{
/*...*/
},
{
// called when comparing array elements
objectHash: function(value: JsonValue, context: GeneratePatchContext) {
// for arrays of primitive values like string and numbers, a stringification is sufficent:
// return JSON.stringify(value)
// If we know the shape of the value, we can match be specific properties
return value.name
objectHash: function (value: JsonValue, context: GeneratePatchContext) {
// for arrays of primitive values like string and numbers, a stringification is sufficent:
// return JSON.stringify(value)
// If we know the shape of the value, we can match be specific properties
return value.name;
},
// called for every property on objects. Can be used to ignore sensitive or irrelevant
// called for every property on objects. Can be used to ignore sensitive or irrelevant
// properties when comparing data.
propertyFilter: function (propertyName: string, context: ObjectHashContext) {
return !['sensitiveProperty'].includes(propertyName);
propertyFilter: function (
propertyName: string,
context: ObjectHashContext
) {
return !['sensitiveProperty'].includes(propertyName);
},
array: {
// When true, no move operations will be created.
// The rersulting patch will not lead to identical objects,
// as postions of array elements can be different!
ignoreMove: true
}
});
```
// When true, no move operations will be created.
// The rersulting patch will not lead to identical objects,
// as postions of array elements can be different!
ignoreMove: true,
},
}
);
```

### Patch Context

Both config function (`objectHash`, `propertyFilter`), receive a context as second parameter.
This allows for granular decision-making on the provided data.

#### Example

```typescript
import {generateJSONPatch, JsonPatchConfig, JsonValue, ObjectHashContext, pathInfo} from 'generate-json-patch';
import {
generateJSONPatch,
JsonPatchConfig,
JsonValue,
ObjectHashContext,
pathInfo,
} from 'generate-json-patch';

const before = {
manufacturer: "Ford",
type: "Granada",
colors: ['red', 'silver', 'yellow'],
engine: [
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.0', hp: 90 },
{ name: 'Cologne V6 2.3', hp: 108 },
{ name: 'Essex V6 3.0', hp: 138 },
]
}
manufacturer: 'Ford',
type: 'Granada',
colors: ['red', 'silver', 'yellow'],
engine: [
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.0', hp: 90 },
{ name: 'Cologne V6 2.3', hp: 108 },
{ name: 'Essex V6 3.0', hp: 138 },
],
};

const after = {
manufacturer: "Ford",
type: "Granada",
colors: ['red', 'silver', 'yellow'],
engine: [
{name: 'Essex V6 3.0', hp: 138},
{name: 'Cologne V6 2.6', hp: 125},
{name: 'Cologne V6 2.0', hp: 90},
{name: 'Cologne V6 2.3', hp: 108},
]
}
manufacturer: 'Ford',
type: 'Granada',
colors: ['red', 'silver', 'yellow'],
engine: [
{ name: 'Essex V6 3.0', hp: 138 },
{ name: 'Cologne V6 2.6', hp: 125 },
{ name: 'Cologne V6 2.0', hp: 90 },
{ name: 'Cologne V6 2.3', hp: 108 },
],
};

const patch = generateJSONPatch(before, after, {
objectHash: function (value: JsonValue, context: ObjectHashContext) {
const {length, last} = pathInfo(context.path)
if (length === 2 && last === 'engine') {
return value.name
}
return JSON.stringify(value)
objectHash: function (value: JsonValue, context: ObjectHashContext) {
const { length, last } = pathInfo(context.path);
if (length === 2 && last === 'engine') {
return value.name;
}
return JSON.stringify(value);
},
});

console.log(patch) // => [
console.log(patch); // => [
// { op: 'replace', path: '/engine/3/hp', value: 138 },
// { op: 'move', from: '/engine/3', path: '/engine/0' }
// ]
```

> For more examples, check out the [tests](./src/index.spec.ts)


27 changes: 9 additions & 18 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,51 @@
## [1.2.4](https://github.com/marcolink/generate-json-patch/compare/v1.2.3...v1.2.4) (2024-09-04)


### Bug Fixes

* ignore key order when comparing objects at max depth ([0c59d87](https://github.com/marcolink/generate-json-patch/commit/0c59d87e358c48d804ec4a5a7e059481bbe64c13))
- ignore key order when comparing objects at max depth ([0c59d87](https://github.com/marcolink/generate-json-patch/commit/0c59d87e358c48d804ec4a5a7e059481bbe64c13))

## [1.2.3](https://github.com/marcolink/generate-json-patch/compare/v1.2.2...v1.2.3) (2024-09-04)


### Bug Fixes

* **maxDepth:** do not return a replace operation for identical array hashes ([128034e](https://github.com/marcolink/generate-json-patch/commit/128034ed26253830a26e385817a66151f522d641))
- **maxDepth:** do not return a replace operation for identical array hashes ([128034e](https://github.com/marcolink/generate-json-patch/commit/128034ed26253830a26e385817a66151f522d641))

## [1.2.2](https://github.com/marcolink/generate-json-patch/compare/v1.2.1...v1.2.2) (2024-09-03)


### Bug Fixes

* respect maxDepth for array values ([623fc53](https://github.com/marcolink/generate-json-patch/commit/623fc53dfb9392381451febd20897bb25363130a))
- respect maxDepth for array values ([623fc53](https://github.com/marcolink/generate-json-patch/commit/623fc53dfb9392381451febd20897bb25363130a))

## [1.2.1](https://github.com/marcolink/generate-json-patch/compare/v1.2.0...v1.2.1) (2024-09-03)


### Bug Fixes

* maxDepth was not respected fully ([196c157](https://github.com/marcolink/generate-json-patch/commit/196c157a302d4318a4ec63a010eb7fc946dd0032))
- maxDepth was not respected fully ([196c157](https://github.com/marcolink/generate-json-patch/commit/196c157a302d4318a4ec63a010eb7fc946dd0032))

# [1.2.0](https://github.com/marcolink/generate-json-patch/compare/v1.1.1...v1.2.0) (2024-09-03)


### Bug Fixes

* linting ([6c689b5](https://github.com/marcolink/generate-json-patch/commit/6c689b579713c5f99ed858fe4f71ca8dca987693))

- linting ([6c689b5](https://github.com/marcolink/generate-json-patch/commit/6c689b579713c5f99ed858fe4f71ca8dca987693))

### Features

* add max depth config ([6ea96bc](https://github.com/marcolink/generate-json-patch/commit/6ea96bcc33e42242bacc127f87ef85051bece0b0))
- add max depth config ([6ea96bc](https://github.com/marcolink/generate-json-patch/commit/6ea96bcc33e42242bacc127f87ef85051bece0b0))

## [1.1.1](https://github.com/marcolink/generate-json-patch/compare/v1.1.0...v1.1.1) (2024-05-22)


### Bug Fixes

* loose json value type ([ead7084](https://github.com/marcolink/generate-json-patch/commit/ead7084670d2c1191000f4c9dd181c7fe5351bef))
- loose json value type ([ead7084](https://github.com/marcolink/generate-json-patch/commit/ead7084670d2c1191000f4c9dd181c7fe5351bef))

# [1.1.0](https://github.com/marcolink/generate-json-patch/compare/v1.0.1...v1.1.0) (2023-09-25)


### Features

* use LCS to find the least required move operations ([c0a1c83](https://github.com/marcolink/generate-json-patch/commit/c0a1c83159c2e2eda9b6cfa271b84b3223ff2b05))
- use LCS to find the least required move operations ([c0a1c83](https://github.com/marcolink/generate-json-patch/commit/c0a1c83159c2e2eda9b6cfa271b84b3223ff2b05))

## [1.0.1](https://github.com/marcolink/generate-json-patch/compare/v1.0.0...v1.0.1) (2023-09-09)


### Bug Fixes

* add changelog ([72e0ee4](https://github.com/marcolink/generate-json-patch/commit/72e0ee4b3404a57427916ea02098aa100a86f876))
- add changelog ([72e0ee4](https://github.com/marcolink/generate-json-patch/commit/72e0ee4b3404a57427916ea02098aa100a86f876))
Loading
Loading