@egjs/list-differ
Advanced tools
Comparing version 0.0.0 to 0.0.1
@@ -1,9 +0,8 @@ | ||
import { DiffResult } from "./types"; | ||
import { DiffResult, ListFormat } from "./types"; | ||
declare class ListDiffer<T> { | ||
private findKeyCallback?; | ||
private list; | ||
private callback; | ||
private mapClass; | ||
constructor(list?: T[], callback?: (e: T, i: number, arr: T[]) => number | string); | ||
update(list: T[]): DiffResult<T>; | ||
constructor(list?: ListFormat<T>, findKeyCallback?: (e: T, i: number, arr: T[]) => number | string); | ||
update(list: ListFormat<T>): DiffResult<T>; | ||
} | ||
export default ListDiffer; |
@@ -1,10 +0,7 @@ | ||
declare const _default: MapConstructor | { | ||
new <T>(): { | ||
keys: T[]; | ||
values: number[]; | ||
has(key: T): boolean; | ||
get(key: T): number; | ||
set(key: T, value: number): void; | ||
}; | ||
}; | ||
export default _default; | ||
export default class PolyMap<T> { | ||
private keys; | ||
private values; | ||
has(key: T): boolean; | ||
get(key: T): number; | ||
set(key: T, value: number): void; | ||
} |
@@ -7,2 +7,6 @@ export interface MapInteface<T, U> { | ||
export declare type MapConstructor<T, U> = new () => MapInteface<T, U>; | ||
export interface ListFormat<T = any> { | ||
[index: number]: T; | ||
length: number; | ||
} | ||
export interface DiffResult<T> { | ||
@@ -9,0 +13,0 @@ prevList: T[]; |
@@ -1,3 +0,3 @@ | ||
import { MapInteface, DiffResult } from "./types"; | ||
import { DiffResult } from "./types"; | ||
export declare function orderChanged(changed: number[][]): void; | ||
export declare function diff<T>(prevList: T[], list: T[], findKeyCallback?: (e: T, i: number, arr: T[]) => any, mapClass?: new () => MapInteface<any, number>): DiffResult<T>; | ||
export declare function diff<T>(prevList: T[], list: T[], findKeyCallback?: (e: T, i: number, arr: T[]) => any): DiffResult<T>; |
{ | ||
"name": "@egjs/list-differ", | ||
"version": "0.0.0", | ||
"description": "A module that checks diff when values are added, removed, or changed in an array.", | ||
"main": "./dist/listdiffer.js", | ||
"module": "./dist/listdiffer.esm.js", | ||
"version": "0.0.1", | ||
"description": "A module that checks the diff when values are added, removed, or changed in an array.", | ||
"main": "./dist/list-differ.js", | ||
"module": "./dist/list-differ.esm.js", | ||
"types": "./declaration/index.d.ts", | ||
"es2015": "dist/listdiffer.esm.js", | ||
"es2015": "dist/list-differ.esm.js", | ||
"sideEffects": false, | ||
@@ -68,4 +68,4 @@ "scripts": { | ||
"tslint": "^5.15.0", | ||
"typescript": "^3.4.1" | ||
"typescript": "^3.0.3" | ||
} | ||
} |
177
README.md
# list-differ [![npm version](https://badge.fury.io/js/%40egjs%2Flist-differ.svg)](https://badge.fury.io/js/%40egjs%2Flist-differ) [![Build Status](https://travis-ci.org/naver/egjs-list-differ.svg?branch=master)](https://travis-ci.org/naver/egjs-list-differ) [![Coverage Status](https://coveralls.io/repos/github/naver/egjs-list-differ/badge.svg?branch=master)](https://coveralls.io/github/naver/egjs-list-differ?branch=master) | ||
A module that detects when values are added, removed, or changed in an array or object. | ||
A module that checks the diff when values are added, removed, or changed in an array. | ||
@@ -11,3 +11,3 @@ ## Installation | ||
## Components | ||
## Related Projects | ||
* [@egjs/children-differ]() | ||
@@ -19,3 +19,3 @@ * [@egjs/react-children-differ]() | ||
## How to use | ||
### Detect a change in array | ||
### checks the diff in array | ||
```js | ||
@@ -26,65 +26,168 @@ import ListDiffer from "@egjs/list-differ"; | ||
// Value is key | ||
const differ = new ListDiffer([0, 1, 2, 3, 4, 5], e => e); | ||
const result = differ.update([7, 8, 0, 4, 3, 6, 2, 1]); | ||
const differ = new ListDiffer([1, 2, 3, 4, 5, 6, 7], e => e); | ||
const result = differ.update([4, 3, 6, 2, 1, 7]); | ||
// List before update | ||
// [1, 2, 3, 4, 5] | ||
// [1, 2, 3, 4, 5, 6, 7] | ||
console.log(result.prevList); | ||
// Updated list | ||
// [4, 3, 6, 2, 1] | ||
console.log(result.data); | ||
// [4, 3, 6, 2, 1, 7] | ||
console.log(result.list); | ||
// Index array of values added to `list` | ||
// [0, 1, 5] | ||
// [2] | ||
console.log(result.added); | ||
// Index array of values removed in `prevList` | ||
// [5] | ||
// [5, 4] | ||
console.log(result.removed); | ||
// Tuple arrays of index of `prevList` and `list` with different indexes from `prevList` and `list` | ||
// [[0, 2], [4, 3], [3, 4], [2, 6], [1, 7]] | ||
// [[3, 0], [2, 1], [1, 3], [0, 4], [6, 5]] | ||
console.log(result.changed); | ||
// Tuple arrays of index of `prevList` and `list` with different indexes from `prevList` and `list` before data is added | ||
// [[4, 3], [3, 4], [2, 6]] | ||
// [[3, 0], [2, 1], [1, 3]] | ||
console.log(result.changedBeforeAdded); | ||
// Tuple arrays of index of `prevList` and `list` with different indexes from `prevList` and `list` after data is added | ||
// [[4, 3], [3, 4], [2, 6], [1, 7]] | ||
// [[3, 0], [2, 1], [1, 3], [0, 4]] | ||
console.log(result.changedAfterAdded); | ||
// Tuple arrays of `prevIndex` and `nextIndex` to change the order of `prevList` to `list` before data is added. | ||
// [[4, 1], [4, 2], [4, 3]] | ||
// [[3, 0], [3, 1], [3, 2]] | ||
console.log(result.orderedBeforeAdded); | ||
// Tuple arrays of `prevIndex` and `nextIndex` to change the order of `prevList` to `list` after data is added | ||
// [[7, 3], [7, 4], [6, 7], [5, 7]] | ||
// [[4, 0], [4, 1], [3, 4], [2, 4]] | ||
console.log(result.orderedAfterAdded); | ||
// Tuple arrays of index of `prevList` and `list` that have not been added/removed so data is preserved | ||
// [[0, 2], [4, 3], [3, 4], [2, 6], [1, 7]] | ||
// [[3, 0], [2, 1], [1, 3], [0, 4], [6, 5]] | ||
console.log(result.maintained); | ||
``` | ||
### What is changed? | ||
Tuple arrays of index of `prevList` and `list` with different indexes from `prevList` and `list` | ||
### Detect a change in children | ||
```html | ||
<div id="container"> | ||
<div>0</div> | ||
<div>1</div> | ||
<div>2</div> | ||
<div>3</div> | ||
<div>4</div> | ||
<div>5</div> | ||
<div>6</div> | ||
</div> | ||
<script> | ||
||changed:| | ||
|---:|---| | ||
||[[3, 0], [2, 1], [1, 3], [0, 4], [6, 5]]| | ||
|prevList|![prev_list](./images/changed_prev_list.png) | | ||
|list|![list](./images/changed_list.png)| | ||
import ListDiffer from "@egjs/list-differ"; | ||
// Value is key | ||
const differ = new ListDiffer(conatiner.children); | ||
### What is beforeAdded, afteradded? | ||
* **beforeAdded**: Obtain a minimum of `changed` in time before data is `added` | ||
* **changedBeforeAdded**: Tuple arrays of index of `prevList` and `list` with different indexes from `prevList` and `list` before data is added | ||
* **orderedBeforeAdded**: Tuple arrays of `prevIndex` and `nextIndex` to change the order of `prevList` to `list` before data is added. | ||
* **afterAdded**: Obtain a minimum of `changed` in time after data is `added` | ||
* **changedAfterAdded**: Tuple arrays of index of `prevList` and `list` with different indexes from `prevList` and `list` after data is added | ||
* **orderedAfterAdded**: Tuple arrays of `prevIndex` and `nextIndex` to change the order of `prevList` to `list` after data is added. | ||
container.removeChild(container.children[5]); | ||
container.removeChild(container.children[2]); | ||
||beforeAdded||afterAdded| | ||
|---:|---|---:|---| | ||
||removed -> ordered -> added||removed -> added -> ordered| | ||
|prevList|![](./images/prev_list.png)|prevList|![](./images/prev_list.png)| | ||
|removed<br/>[5, 4]|![](./images/removed.png)|removed<br/>[5, 4]|![](./images/removed.png)| | ||
|||added<br/>[2]|![](./images/ordered_after_added.png)| | ||
||**orderedBeforeAdded:**||**orderedAfterAdded:**| | ||
||[[3, 0], [3, 1], [3, 2]]||[[4, 0], [4, 1], [3, 4], [2, 4]]| | ||
|ordered0<br/>[3 => 0]| ![](./images/ordered_before_ordered0.png)|ordered0<br/>[4 => 0]|![](./images/ordered_after_ordered0.png)| | ||
|ordered1<br/>[3 => 1]| ![](./images/ordered_before_ordered1.png)|ordered1<br/>[4 => 1]|![](./images/ordered_after_ordered1.png)| | ||
|ordered2<br/>[3 => 2]| ![](./images/ordered_before_ordered2.png)|ordered2<br/>[3 => 4]|![](./images/ordered_after_ordered2.png)| | ||
|||ordered3<br/>[2 => 4]|![](./images/ordered_after_ordered3.png)| | ||
|added<br/>[2]|![](./images/ordered_before_added.png)||| | ||
|list|![](./images/list.png)|list|![](./images/list.png)| | ||
||**changedBeforeAdded:**||**chanedAfterAdded:**| | ||
||[[3, 0], [2, 1], [1, 3]]||[[3, 0], [2, 1], [1, 3], [0, 4]]| | ||
|prevList|![](./images/changed_before_prev_list.png)|prevList|![](./images/changed_after_prev_list.png)| | ||
|process|![](./images/changed_before_animation.gif)|process|![](./images/changed_after_animation.gif)| | ||
|list|![](./images/changed_before_list.png)|list|![](./images/changed_after_list.png)| | ||
const result = differ.update(container.children); | ||
// [4, 2] | ||
console.log(result.removed); | ||
</script> | ||
## Examples for (prevList => list) | ||
```js | ||
import ListDiffer, { diff } from "@egjs/list-differ"; | ||
const prevList = [1, 2, 3, 4, 5, 6, 7]; | ||
const list = [4, 3, 6, 2, 1, 7]; | ||
const result = diff(prevList, list, e => e); | ||
``` | ||
### prevList => (removed => orderedBeforeAdded => added) => list | ||
||removed => orderedBeforeAdded => added| | ||
|---|---| | ||
|prevList|![](./images/prev_list.png)| | ||
|process|![](./images/changed_before_animation.gif)| | ||
|list|![](./images/list.png)| | ||
```js | ||
const nextList = prevList.slice(); | ||
result.removed.forEach(index => { | ||
nextList.splice(index, 1); | ||
}); | ||
result.orderedBeforeAdded.forEach(([from, to], i) => { | ||
nextList.splice(from, 1); | ||
nextList.splice(to, 0, list[result.changedBeforeAdded[i][1]]); | ||
}); | ||
result.added.forEach(index => { | ||
nextList.splice(index, 0, list[index]); | ||
}); | ||
// `nextList` is the same as `list`. | ||
console.log(nextList); | ||
``` | ||
### prevList => (removed => added => orderdAfterAdded) => list | ||
||removed => added => orderdAfterAdded| | ||
|---|---| | ||
|prevList|![](./images/prev_list.png)| | ||
|process|![](./images/changed_after_animation.gif)| | ||
|list|![](./images/list.png)| | ||
```js | ||
const nextList = prevList.slice(); | ||
result.removed.forEach(index => { | ||
nextList.splice(index, 1); | ||
}); | ||
result.added.forEach(index => { | ||
nextList.splice(index, 0, list[index]); | ||
}); | ||
result.orderedAfterAdded.forEach(([from, to], i) => { | ||
nextList.splice(from, 1); | ||
nextList.splice(to, 0, list[result.changedAfterAdded[i][1]]); | ||
}); | ||
// `nextList` is the same as `list`. | ||
console.log(nextList); | ||
``` | ||
### prevList => (maintained => added) => list | ||
||maintained => added| | ||
|---|---| | ||
|prevList|![](./images/prev_list.png)| | ||
|process|![](./images/maintained_added.gif)| | ||
|list|![](./images/list.png)| | ||
```js | ||
const nextList = []; | ||
result.maintained.forEach(([from, to]) => { | ||
nextList.push(list[to]); | ||
}); | ||
result.added.forEach(index => { | ||
nextList.splice(index, 0, list[index]); | ||
}); | ||
// `nextList` is the same as `list`. | ||
console.log(nextList); | ||
``` | ||
### prevList => (added => maintaind) => list | ||
||added => maintaind| | ||
|---|---| | ||
|prevList|![](./images/prev_list.png)| | ||
|process|![](./images/added_maintained.gif)| | ||
|list|![](./images/list.png)| | ||
```js | ||
const nextList = []; | ||
result.added.forEach(index => { | ||
nextList.push(list[index]); | ||
}); | ||
result.maintained.forEach(([from, to]) => { | ||
nextList.splice(to, 0, list[to]); | ||
}); | ||
// `nextList` is the same as `list`. | ||
console.log(nextList); | ||
``` | ||
## Bug Report | ||
@@ -91,0 +194,0 @@ |
@@ -13,3 +13,3 @@ | ||
input: "./src/index.ts", | ||
output: "./dist/listdiffer.esm.js", | ||
output: "./dist/list-differ.esm.js", | ||
format: "es", | ||
@@ -20,7 +20,7 @@ exports: "named", | ||
...defaultOptions, | ||
output: "./dist/listdiffer.js", | ||
output: "./dist/list-differ.js", | ||
}, | ||
{ | ||
...defaultOptions, | ||
output: "./dist/listdiffer.min.js", | ||
output: "./dist/list-differ.min.js", | ||
uglify: true, | ||
@@ -30,3 +30,3 @@ }, | ||
...defaultOptions, | ||
output: "./dist/listdiffer.pkgd.js", | ||
output: "./dist/list-differ.pkgd.js", | ||
resolve: true, | ||
@@ -36,3 +36,3 @@ }, | ||
...defaultOptions, | ||
output: "./dist/listdiffer.pkgd.min.js", | ||
output: "./dist/list-differ.pkgd.min.js", | ||
resolve: true, | ||
@@ -39,0 +39,0 @@ uglify: true, |
@@ -1,9 +0,7 @@ | ||
import HashMap from "./HashMap"; | ||
import PolyMap from "./PolyMap"; | ||
import { DiffResult } from "./types"; | ||
import { DiffResult, ListFormat } from "./types"; | ||
import { diff } from "./utils"; | ||
/** | ||
* A module that detects when values are added, removed, or changed in an array or object. | ||
* @ko 배열 또는 오브젝트에서 값이 추가되거나 삭제되거나 순서가 변경된 경우를 감지하는 모듈입니다. | ||
* A module that checks diff when values are added, removed, or changed in an array. | ||
* @ko 배열 또는 오브젝트에서 값이 추가되거나 삭제되거나 순서가 변경사항을 체크하는 모듈입니다. | ||
* @memberof eg | ||
@@ -13,4 +11,2 @@ */ | ||
private list: T[]; | ||
private callback: (e: T, i: number, arr: T[]) => any; | ||
private mapClass: typeof HashMap | typeof PolyMap; | ||
/** | ||
@@ -29,3 +25,3 @@ * @param - Initializing Data Array <ko> 초기 설정할 데이터 배열 </ko> | ||
* // [4, 3, 6, 2, 1] | ||
* console.log(result.data); | ||
* console.log(result.list); | ||
* // Index array of values added to `list` | ||
@@ -57,8 +53,6 @@ * // [0, 1, 5] | ||
constructor( | ||
list: T[] = [], | ||
callback?: (e: T, i: number, arr: T[]) => number | string, | ||
list: ListFormat<T> = [], | ||
private findKeyCallback?: (e: T, i: number, arr: T[]) => number | string, | ||
) { | ||
this.list = [].slice.call(list); | ||
this.mapClass = callback ? HashMap : PolyMap; | ||
this.callback = callback || ((e: T) => e); | ||
} | ||
@@ -71,5 +65,5 @@ /** | ||
*/ | ||
public update(list: T[]): DiffResult<T> { | ||
const newData = [].slice.call(list); | ||
const result = diff<T>(this.list, newData, this.callback, this.mapClass); | ||
public update(list: ListFormat<T>): DiffResult<T> { | ||
const newData: T[] = [].slice.call(list); | ||
const result = diff<T>(this.list, newData, this.findKeyCallback); | ||
@@ -76,0 +70,0 @@ this.list = newData; |
@@ -1,2 +0,2 @@ | ||
export default typeof Map !== "undefined" ? Map : class PolyMap<T> { | ||
export default class PolyMap<T> { | ||
private keys: T[] = []; | ||
@@ -3,0 +3,0 @@ private values: number[] = []; |
@@ -7,3 +7,6 @@ export interface MapInteface<T, U> { | ||
export type MapConstructor<T, U> = new () => MapInteface <T, U>; | ||
export interface ListFormat<T = any> { | ||
[index: number]: T; | ||
length: number; | ||
} | ||
/** | ||
@@ -10,0 +13,0 @@ * @typedef |
import { MapInteface, DiffResult } from "./types"; | ||
import PolyMap from "./PolyMap"; | ||
import HashMap from "./HashMap"; | ||
import {SUPPORT_MAP} from "./consts"; | ||
export function orderChanged(changed: number[][]) { | ||
@@ -26,5 +28,6 @@ changed.forEach(([from, to], i)=> { | ||
list: T[], | ||
findKeyCallback: (e: T, i: number, arr: T[]) => any = ((e: T) => e), | ||
mapClass: new () => MapInteface<any, number> = findKeyCallback ? HashMap : PolyMap, | ||
findKeyCallback?: (e: T, i: number, arr: T[]) => any | ||
): DiffResult<T> { | ||
const mapClass: new () => MapInteface<any, number> = SUPPORT_MAP ? Map : (findKeyCallback ? HashMap : PolyMap); | ||
const callback = findKeyCallback || ((e: T) => e); | ||
const added: number[] = []; | ||
@@ -34,4 +37,4 @@ const removed: number[] = []; | ||
const changed: number[][] = []; | ||
const prevKeys = prevList.map(findKeyCallback); | ||
const keys = list.map(findKeyCallback); | ||
const prevKeys = prevList.map(callback); | ||
const keys = list.map(callback); | ||
const prevKeyMap: MapInteface<any, number> = new mapClass(); | ||
@@ -38,0 +41,0 @@ const keyMap: MapInteface<any, number> = new mapClass(); |
2406563
80
219
2456