import {
LIST_STATUS ,
ListDiff ,
ListData ,
ListDiffStatus ,
ListOptions ,
} from "./model" ;
import { isEqual } from "./utils" ;
function getLeanDiff (
diff : ListDiff [ "diff" ] ,
showOnly = [ ] as ListOptions [ "showOnly" ]
) : ListDiff [ "diff" ] {
return diff . filter ( ( value ) = > showOnly ? . includes ( value . status ) ) ;
}
function formatSingleListDiff (
listData : ListData [ ] ,
status : ListDiffStatus
) : ListDiff {
return {
type : "list" ,
status ,
diff : listData.map ( ( data : ListData , i ) = > ( {
value : data ,
prevIndex : status === LIST_STATUS . ADDED ? null : i ,
newIndex : status === LIST_STATUS . ADDED ? i : null ,
indexDiff : null ,
status ,
} ) ) ,
} ;
}
function getListStatus ( listDiff : ListDiff [ "diff" ] ) : ListDiffStatus {
return listDiff . some ( ( value ) = > value . status !== LIST_STATUS . EQUAL )
? LIST_STATUS . UPDATED
: LIST_STATUS . EQUAL ;
}
export const getListDiff = (
prevList : ListData [ ] | undefined | null ,
nextList : ListData [ ] | undefined | null ,
options : ListOptions = { showOnly : [ ] }
) : ListDiff = > {
if ( ! prevList && ! nextList ) {
return {
type : "list" ,
status : LIST_STATUS.EQUAL ,
diff : [ ] ,
} ;
}
if ( ! prevList ) {
return formatSingleListDiff ( nextList as ListData , LIST_STATUS . ADDED ) ;
}
if ( ! nextList ) {
return formatSingleListDiff ( prevList as ListData , LIST_STATUS . DELETED ) ;
}
const diff : ListDiff [ "diff" ] = [ ] ;
const prevIndexMatches : number [ ] = [ ] ;
nextList . forEach ( ( nextValue , i ) = > {
const prevIndex = prevList . findIndex (
( prevValue , prevIdx ) = >
isEqual ( prevValue , nextValue ) && ! prevIndexMatches . includes ( prevIdx )
) ;
if ( prevIndex > - 1 ) {
prevIndexMatches . push ( prevIndex ) ;
}
const indexDiff = prevIndex === - 1 ? null : i - prevIndex ;
if ( indexDiff === 0 ) {
return diff . push ( {
value : nextValue ,
prevIndex ,
newIndex : i ,
indexDiff ,
status : LIST_STATUS.EQUAL ,
} ) ;
}
if ( prevIndex === - 1 ) {
return diff . push ( {
value : nextValue ,
prevIndex : null ,
newIndex : i ,
indexDiff ,
status : LIST_STATUS.ADDED ,
} ) ;
}
return diff . push ( {
value : nextValue ,
prevIndex ,
newIndex : i ,
indexDiff ,
status : LIST_STATUS.MOVED ,
} ) ;
} ) ;
prevList . forEach ( ( prevValue , i ) = > {
if ( ! prevIndexMatches . includes ( i ) ) {
return diff . splice ( i , 0 , {
value : prevValue ,
prevIndex : i ,
newIndex : null ,
indexDiff : null ,
status : LIST_STATUS.DELETED ,
} ) ;
}
} ) ;
if ( options . showOnly && options ? . showOnly ? . length > 0 ) {
return {
type : "list" ,
status : getListStatus ( diff ) ,
diff : getLeanDiff ( diff , options . showOnly ) ,
} ;
}
return {
type : "list" ,
status : getListStatus ( diff ) ,
diff ,
} ;
} ;