Skip to content

Commit 93005cc

Browse files
author
aikoven
committed
chore: check-in
0 parents  commit 93005cc

File tree

15 files changed

+3208
-0
lines changed

15 files changed

+3208
-0
lines changed

.github/workflows/ci.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
build:
13+
name: Test and Build
14+
15+
runs-on: ubuntu-latest
16+
17+
strategy:
18+
matrix:
19+
node-version:
20+
- 12.x
21+
- 14.x
22+
- 16.x
23+
24+
steps:
25+
- uses: actions/checkout@v2
26+
- name: Use Node.js ${{ matrix.node-version }}
27+
uses: actions/setup-node@v1
28+
with:
29+
node-version: ${{ matrix.node-version }}
30+
- run: yarn --frozen-lockfile
31+
- run: yarn build
32+
- run: yarn test

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
lib
3+
coverage
4+
.DS_Store
5+
.vscode

.prettierrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"singleQuote": true,
3+
"bracketSpacing": false,
4+
"trailingComma": "all",
5+
"proseWrap": "always",
6+
"arrowParens": "avoid",
7+
"endOfLine": "auto"
8+
}

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2021 Deeplay
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# diff-maps [![npm version][npm-image]][npm-url] <!-- omit in toc -->
2+
3+
Calculate diff between two `Map`s
4+
5+
- [Installation](#installation)
6+
- [Usage](#usage)
7+
8+
## Installation
9+
10+
```
11+
npm install diff-maps
12+
```
13+
14+
## Usage
15+
16+
Calculate diff:
17+
18+
```ts
19+
import {diffMaps} from 'diff-maps';
20+
21+
expect(
22+
diffMaps(
23+
new Map([
24+
['1', 0],
25+
['2', 0],
26+
]),
27+
new Map([
28+
['2', 1],
29+
['3', 1],
30+
]),
31+
),
32+
).toEqual([
33+
{type: 'remove', key: '1', prevValue: 0},
34+
{type: 'change', key: '2', value: 1, prevValue: 0},
35+
{type: 'add', key: '3', value: 1},
36+
]);
37+
```
38+
39+
Use custom equality function (default is
40+
[`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)):
41+
42+
```ts
43+
import {diffMaps} from 'diff-maps';
44+
import {isEqual} from 'lodash';
45+
46+
expect(
47+
diffMaps(
48+
new Map([
49+
['1', {data: 0}],
50+
['2', {data: 0}],
51+
]),
52+
new Map([
53+
['1', {data: 0}],
54+
['2', {data: 1}],
55+
]),
56+
isEqual,
57+
),
58+
).toEqual([
59+
{
60+
type: 'change',
61+
key: '2',
62+
value: {data: 1},
63+
prevValue: {data: 0},
64+
},
65+
]);
66+
```
67+
68+
Apply diff:
69+
70+
```ts
71+
import {applyDiff} from 'diff-maps';
72+
73+
const state = new Map([
74+
['1', 0],
75+
['2', 0],
76+
]);
77+
78+
// mutates the map
79+
applyDiff(state, [
80+
{type: 'remove', key: '1', prevValue: 0},
81+
{type: 'change', key: '2', value: 1, prevValue: 0},
82+
{type: 'add', key: '3', value: 1},
83+
]);
84+
85+
expect(state).toEqual(
86+
new Map([
87+
['2', 1],
88+
['3', 1],
89+
]),
90+
);
91+
```
92+
93+
Use with [Immutable.js](https://github.com/immutable-js/immutable-js):
94+
95+
```ts
96+
import {Map} from 'immutable';
97+
98+
// calculate diff
99+
100+
expect(
101+
diffMaps(
102+
Map({
103+
1: 0,
104+
2: 0,
105+
}),
106+
Map({
107+
2: 1,
108+
3: 1,
109+
}),
110+
),
111+
).toEqual([
112+
{type: 'remove', key: '1', prevValue: 0},
113+
{type: 'change', key: '2', value: 1, prevValue: 0},
114+
{type: 'add', key: '3', value: 1},
115+
]);
116+
117+
// apply diff
118+
119+
const state = Map({
120+
1: 0,
121+
2: 0,
122+
});
123+
124+
const nextState = state.withMutations(mutableState => {
125+
applyDiff(mutableState, [
126+
{type: 'remove', key: '1', prevValue: 0},
127+
{type: 'change', key: '2', value: 1, prevValue: 0},
128+
{type: 'add', key: '3', value: 1},
129+
]);
130+
});
131+
132+
expect(new Map(nextState)).toEqual(
133+
new Map([
134+
['2', 1],
135+
['3', 1],
136+
]),
137+
);
138+
```
139+
140+
[npm-image]: https://badge.fury.io/js/diff-maps.svg
141+
[npm-url]: https://badge.fury.io/js/diff-maps

jest.config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module.exports = {
2+
testPathIgnorePatterns: ['/node_modules/', '/lib/'],
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
collectCoverage: true,
6+
coverageDirectory: 'coverage',
7+
coverageReporters: ['lcov', 'text'],
8+
coveragePathIgnorePatterns: ['/node_modules/', '/lib/'],
9+
};

package.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "diff-maps",
3+
"version": "0.1.0",
4+
"description": "Calculate diff between two Maps",
5+
"keywords": [
6+
"map",
7+
"diff",
8+
"changes"
9+
],
10+
"repository": "deeplay-io/diff-maps",
11+
"main": "lib/index.js",
12+
"typings": "lib/index.d.ts",
13+
"files": [
14+
"lib",
15+
"src",
16+
"!src/**/*.test.ts",
17+
"!src/**/__tests__"
18+
],
19+
"scripts": {
20+
"clean": "rimraf lib",
21+
"test": "jest",
22+
"build": "tsc -P tsconfig.build.json",
23+
"prepublishOnly": "npm run clean && npm run build && npm test"
24+
},
25+
"author": "Daniel Lytkin <aikoven@deeplay.io>",
26+
"license": "MIT",
27+
"devDependencies": {
28+
"@tsconfig/recommended": "^1.0.1",
29+
"@types/jest": "^26.0.24",
30+
"immutable": "^4.0.0-rc.14",
31+
"jest": "^27.0.6",
32+
"prettier": "^2.3.2",
33+
"rimraf": "^2.6.3",
34+
"ts-jest": "^27.0.4",
35+
"typescript": "~4.3.2"
36+
},
37+
"dependencies": {}
38+
}

src/apply.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {Map as ImmutableMap} from 'immutable';
2+
import {applyDiff} from './apply';
3+
4+
test('basic', () => {
5+
const state = new Map([
6+
['1', 0],
7+
['2', 0],
8+
]);
9+
10+
applyDiff(state, [
11+
{type: 'remove', key: '1', prevValue: 0},
12+
{type: 'change', key: '2', value: 1, prevValue: 0},
13+
{type: 'add', key: '3', value: 1},
14+
]);
15+
16+
expect(state).toEqual(
17+
new Map([
18+
['2', 1],
19+
['3', 1],
20+
]),
21+
);
22+
});
23+
24+
test('immutable', () => {
25+
const state = ImmutableMap({
26+
1: 0,
27+
2: 0,
28+
});
29+
30+
const nextState = state.withMutations(state => {
31+
applyDiff(state, [
32+
{type: 'remove', key: '1', prevValue: 0},
33+
{type: 'change', key: '2', value: 1, prevValue: 0},
34+
{type: 'add', key: '3', value: 1},
35+
]);
36+
});
37+
38+
expect(new Map(nextState)).toEqual(
39+
new Map([
40+
['2', 1],
41+
['3', 1],
42+
]),
43+
);
44+
});

src/apply.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {DiffItem} from './diff';
2+
3+
export type WriteonlyMap<K, V> = {
4+
set(key: K, value: V): unknown;
5+
delete(key: K): unknown;
6+
};
7+
8+
export function applyDiff<Key, Value>(
9+
state: WriteonlyMap<Key, Value>,
10+
diff: Array<DiffItem<Key, Value>>,
11+
): void {
12+
for (const item of diff) {
13+
if (item.type === 'add' || item.type === 'change') {
14+
state.set(item.key, item.value);
15+
} else if (item.type === 'remove') {
16+
state.delete(item.key);
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)