@ -1,42 +1,25 @@
import {
import {
GRANULARITY ,
GRANULARITY ,
STATUS ,
OBJECT_ STATUS,
ObjectData ,
ObjectData ,
ObjectDiff ,
ObjectDiff ,
ObjectDiffStatu s ,
ObjectDiffOption s ,
ObjectOptions ,
Diff ,
SubProperties ,
DEFAULT_OBJECT_DIFF_OPTIONS ,
} from "./model" ;
} from "./models/object " ;
import { isEqual , isObject } from "./utils" ;
import { isEqual , isObject } from "./utils" ;
function getLeanDiff (
function getLeanDiff (
diff : ObjectDiff [ "diff" ] ,
diff : ObjectDiff [ "diff" ] ,
showOnly : ObjectOptions [ "showOnly" ] = {
showOnly : ObjectDiffOptions [ "showOnly" ] = DEFAULT_OBJECT_DIFF_OPTIONS . showOnly ,
statuses : [ ] ,
granularity : GRANULARITY.BASIC ,
} ,
) : ObjectDiff [ "diff" ] {
) : ObjectDiff [ "diff" ] {
const { statuses , granularity } = showOnly ;
const { statuses , granularity } = showOnly ;
return diff . reduce (
return diff . reduce (
( acc , value ) = > {
( acc , value ) = > {
if ( granularity === GRANULARITY . DEEP && value . subPropertiesDiff ) {
if ( granularity === GRANULARITY . DEEP && value . diff ) {
const cleanSubPropertiesDiff = getLeanDiff (
const leanDiff = getLeanDiff ( value . diff , showOnly ) ;
value . subPropertiesDiff ,
if ( leanDiff . length > 0 ) {
showOnly ,
return [ . . . acc , { . . . value , diff : leanDiff } ] ;
) ;
if ( cleanSubPropertiesDiff . length > 0 ) {
return [
. . . acc ,
{ . . . value , subPropertiesDiff : cleanSubPropertiesDiff } ,
] ;
}
}
// @ts-ignore
if ( granularity === GRANULARITY . DEEP && value . subDiff ) {
// @ts-ignore
const cleanSubDiff = getLeanDiff ( value . subDiff , showOnly ) ;
if ( cleanSubDiff . length > 0 ) {
return [ . . . acc , { . . . value , subDiff : cleanSubDiff } ] ;
}
}
}
}
if ( statuses . includes ( value . status ) ) {
if ( statuses . includes ( value . status ) ) {
@ -48,51 +31,50 @@ function getLeanDiff(
) ;
) ;
}
}
function getObjectStatus ( diff : ObjectDiff [ "diff" ] ) : ObjectDiffStatus {
function getObjectStatus ( diff : ObjectDiff [ "diff" ] ) : OBJECT_STATUS {
return diff . some ( ( property ) = > property . status !== STATUS . EQUAL )
return diff . some ( ( property ) = > property . status !== OBJECT_ STATUS. EQUAL )
? STATUS . UPDATED
? OBJECT_ STATUS. UPDATED
: STATUS . EQUAL ;
: OBJECT_ STATUS. EQUAL ;
}
}
function formatSingleObjectDiff (
function formatSingleObjectDiff (
data : ObjectData ,
data : ObjectData ,
status : ObjectDiffStatus ,
status : OBJECT_STATUS ,
options : ObjectOptions = {
options : ObjectDiffOptions = DEFAULT_OBJECT_DIFF_OPTIONS ,
ignoreArrayOrder : false ,
showOnly : { statuses : [ ] , granularity : GRANULARITY.BASIC } ,
} ,
) : ObjectDiff {
) : ObjectDiff {
if ( ! data ) {
if ( ! data ) {
return {
return {
type : "object" ,
type : "object" ,
status : STATUS.EQUAL ,
status : OBJECT_ STATUS.EQUAL,
diff : [ ] ,
diff : [ ] ,
} ;
} ;
}
}
const diff : ObjectDiff [ "diff" ] = [ ] ;
const diff : ObjectDiff [ "diff" ] = [ ] ;
Object . entries ( data ) . forEach ( ( [ property , value ] ) = > {
Object . entries ( data ) . forEach ( ( [ property , value ] ) = > {
if ( isObject ( value ) ) {
if ( isObject ( value ) ) {
const subPropertiesDiff : SubProperties [ ] = [ ] ;
const subPropertiesDiff : Diff [ ] = [ ] ;
Object . entries ( value ) . forEach ( ( [ subProperty , subValue ] ) = > {
Object . entries ( value ) . forEach ( ( [ subProperty , subValue ] ) = > {
subPropertiesDiff . push ( {
subPropertiesDiff . push ( {
property : subProperty ,
property : subProperty ,
previousValue : status === STATUS . ADDED ? undefined : subValue ,
previousValue : status === OBJECT_ STATUS. ADDED ? undefined : subValue ,
currentValue : status === STATUS . ADDED ? subValue : undefined ,
currentValue : status === OBJECT_ STATUS. ADDED ? subValue : undefined ,
status ,
status ,
} ) ;
} ) ;
} ) ;
} ) ;
return diff . push ( {
return diff . push ( {
property : property ,
property ,
previousValue : status === STATUS . ADDED ? undefined : data [ property ] ,
previousValue :
currentValue : status === STATUS . ADDED ? value : undefined ,
status === OBJECT_STATUS . ADDED ? undefined : data [ property ] ,
currentValue : status === OBJECT_STATUS . ADDED ? value : undefined ,
status ,
status ,
subPropertiesDiff ,
diff : subPropertiesDiff ,
} ) ;
} ) ;
}
}
return diff . push ( {
return diff . push ( {
property ,
property ,
previousValue : status === STATUS . ADDED ? undefined : data [ property ] ,
previousValue :
currentValue : status === STATUS . ADDED ? value : undefined ,
status === OBJECT_STATUS . ADDED ? undefined : data [ property ] ,
currentValue : status === OBJECT_STATUS . ADDED ? value : undefined ,
status ,
status ,
} ) ;
} ) ;
} ) ;
} ) ;
@ -111,10 +93,10 @@ function formatSingleObjectDiff(
}
}
function getPreviousMatch (
function getPreviousMatch (
previousValue : any | undefined ,
previousValue : unknown | undefined ,
nextSubProperty : any ,
nextSubProperty : unknown ,
options? : ObjectOptions ,
options? : ObjectDiff Options ,
) : any | undefined {
) : unknown | undefined {
if ( ! previousValue ) {
if ( ! previousValue ) {
return undefined ;
return undefined ;
}
}
@ -125,28 +107,28 @@ function getPreviousMatch(
}
}
function getValueStatus (
function getValueStatus (
previousValue : any ,
previousValue : unknown ,
nextValue : any ,
nextValue : unknown ,
options? : ObjectOptions ,
options? : ObjectDiff Options ,
) : ObjectDiffStatus {
) : OBJECT_STATUS {
if ( isEqual ( previousValue , nextValue , options ) ) {
if ( isEqual ( previousValue , nextValue , options ) ) {
return STATUS . EQUAL ;
return OBJECT_ STATUS. EQUAL ;
}
}
return STATUS . UPDATED ;
return OBJECT_ STATUS. UPDATED ;
}
}
function getPropertyStatus (
function getPropertyStatus ( subPropertiesDiff : Diff [ ] ) : OBJECT_STATUS {
subPropertiesDiff : SubProperties [ ] ,
return subPropertiesDiff . some (
) : ObjectDiffStatus {
( property ) = > property . status !== OBJECT_STATUS . EQUAL ,
return subPropertiesDiff . some ( ( property ) = > property . status !== STATUS . EQUAL )
)
? STATUS . UPDATED
? OBJECT_ STATUS. UPDATED
: STATUS . EQUAL ;
: OBJECT_ STATUS. EQUAL ;
}
}
function getDeletedProperties (
function getDeletedProperties (
previousValue : Record < string , any > | undefined ,
previousValue : Record < string , unknown > | undefined ,
nextValue : Record < string , any > ,
nextValue : Record < string , unknown > ,
) : { property : string ; value : any } [ ] | undefined {
) : { property : string ; value : unknown } [ ] | undefined {
if ( ! previousValue ) return undefined ;
if ( ! previousValue ) return undefined ;
const prevKeys = Object . keys ( previousValue ) ;
const prevKeys = Object . keys ( previousValue ) ;
const nextKeys = Object . keys ( nextValue ) ;
const nextKeys = Object . keys ( nextValue ) ;
@ -161,12 +143,12 @@ function getDeletedProperties(
}
}
function getSubPropertiesDiff (
function getSubPropertiesDiff (
previousValue : Record < string , any > | undefined ,
previousValue : Record < string , unknown > | undefined ,
nextValue : Record < string , any > ,
nextValue : Record < string , unknown > ,
options? : ObjectOptions ,
options? : ObjectDiff Options ,
) : SubProperties [ ] {
) : Diff [ ] {
const subPropertiesDiff : SubProperties [ ] = [ ] ;
const subPropertiesDiff : Diff [ ] = [ ] ;
let subDiff : SubProperties [ ] ;
let subDiff : Diff [ ] ;
const deletedMainSubProperties = getDeletedProperties (
const deletedMainSubProperties = getDeletedProperties (
previousValue ,
previousValue ,
nextValue ,
nextValue ,
@ -177,7 +159,7 @@ function getSubPropertiesDiff(
property : deletedProperty.property ,
property : deletedProperty.property ,
previousValue : deletedProperty.value ,
previousValue : deletedProperty.value ,
currentValue : undefined ,
currentValue : undefined ,
status : STATUS.DELETED ,
status : OBJECT_ STATUS.DELETED,
} ) ;
} ) ;
} ) ;
} ) ;
}
}
@ -194,15 +176,15 @@ function getSubPropertiesDiff(
currentValue : nextSubValue ,
currentValue : nextSubValue ,
status :
status :
! previousValue || ! ( nextSubProperty in previousValue )
! previousValue || ! ( nextSubProperty in previousValue )
? STATUS . ADDED
? OBJECT_ STATUS. ADDED
: previousMatch === nextSubValue
: previousMatch === nextSubValue
? STATUS . EQUAL
? OBJECT_ STATUS. EQUAL
: STATUS . UPDATED ,
: OBJECT_ STATUS. UPDATED ,
} ) ;
} ) ;
}
}
if ( isObject ( nextSubValue ) ) {
if ( isObject ( nextSubValue ) ) {
const data : SubProperties [ ] = getSubPropertiesDiff (
const data : Diff [ ] = getSubPropertiesDiff (
previousMatch ,
previousMatch as Record < string , unknown > ,
nextSubValue ,
nextSubValue ,
options ,
options ,
) ;
) ;
@ -216,7 +198,7 @@ function getSubPropertiesDiff(
previousValue : previousMatch ,
previousValue : previousMatch ,
currentValue : nextSubValue ,
currentValue : nextSubValue ,
status : getValueStatus ( previousMatch , nextSubValue , options ) ,
status : getValueStatus ( previousMatch , nextSubValue , options ) ,
. . . ( ! ! subDiff && { subDiff } ) ,
. . . ( ! ! subDiff && { diff : subDiff } ) ,
} ) ;
} ) ;
}
}
} ) ;
} ) ;
@ -225,9 +207,9 @@ function getSubPropertiesDiff(
/ * *
/ * *
* Returns the diff between two objects
* Returns the diff between two objects
* @param { Record < string , any > } prevData - The original object .
* @param { ObjectData } prevData - The original object .
* @param { Record < string , any > } nextData - The new object .
* @param { ObjectData } nextData - The new object .
* * @param { Lis tOptions} options - Options to refine your output .
* * @param { Objec tOptions} options - Options to refine your output .
- ` showOnly ` : returns only the values whose status you are interested in . It takes two parameters : ` statuses ` and ` granularity `
- ` showOnly ` : returns only the values whose status you are interested in . It takes two parameters : ` statuses ` and ` granularity `
` statuses ` are the status you want to see in the output ( e . g . ` ["added", "equal"] ` )
` statuses ` are the status you want to see in the output ( e . g . ` ["added", "equal"] ` )
` granularity ` can be either ` basic ` ( to return only the main properties whose status matches your query ) or ` deep ` ( to return the main properties if some of their subproperties ' status match your request . The subproperties are filtered accordingly ) .
` granularity ` can be either ` basic ` ( to return only the main properties whose status matches your query ) or ` deep ` ( to return the main properties if some of their subproperties ' status match your request . The subproperties are filtered accordingly ) .
@ -237,23 +219,20 @@ function getSubPropertiesDiff(
export function getObjectDiff (
export function getObjectDiff (
prevData : ObjectData ,
prevData : ObjectData ,
nextData : ObjectData ,
nextData : ObjectData ,
options : ObjectOptions = {
options : ObjectDiffOptions = DEFAULT_OBJECT_DIFF_OPTIONS ,
ignoreArrayOrder : false ,
showOnly : { statuses : [ ] , granularity : GRANULARITY.BASIC } ,
} ,
) : ObjectDiff {
) : ObjectDiff {
if ( ! prevData && ! nextData ) {
if ( ! prevData && ! nextData ) {
return {
return {
type : "object" ,
type : "object" ,
status : STATUS.EQUAL ,
status : OBJECT_ STATUS.EQUAL,
diff : [ ] ,
diff : [ ] ,
} ;
} ;
}
}
if ( ! prevData ) {
if ( ! prevData ) {
return formatSingleObjectDiff ( nextData , STATUS . ADDED , options ) ;
return formatSingleObjectDiff ( nextData , OBJECT_ STATUS. ADDED , options ) ;
}
}
if ( ! nextData ) {
if ( ! nextData ) {
return formatSingleObjectDiff ( prevData , STATUS . DELETED , options ) ;
return formatSingleObjectDiff ( prevData , OBJECT_ STATUS. DELETED , options ) ;
}
}
const diff : ObjectDiff [ "diff" ] = [ ] ;
const diff : ObjectDiff [ "diff" ] = [ ] ;
Object . entries ( nextData ) . forEach ( ( [ nextProperty , nextValue ] ) = > {
Object . entries ( nextData ) . forEach ( ( [ nextProperty , nextValue ] ) = > {
@ -264,15 +243,15 @@ export function getObjectDiff(
previousValue ,
previousValue ,
currentValue : nextValue ,
currentValue : nextValue ,
status : ! ( nextProperty in prevData )
status : ! ( nextProperty in prevData )
? STATUS . ADDED
? OBJECT_ STATUS. ADDED
: previousValue === nextValue
: previousValue === nextValue
? STATUS . EQUAL
? OBJECT_ STATUS. EQUAL
: STATUS . UPDATED ,
: OBJECT_ STATUS. UPDATED ,
} ) ;
} ) ;
}
}
if ( isObject ( nextValue ) ) {
if ( isObject ( nextValue ) ) {
const subPropertiesDiff : SubProperties [ ] = getSubPropertiesDiff (
const subPropertiesDiff : Diff [ ] = getSubPropertiesDiff (
previousValue ,
previousValue as Record < string , unknown > ,
nextValue ,
nextValue ,
options ,
options ,
) ;
) ;
@ -282,7 +261,9 @@ export function getObjectDiff(
previousValue ,
previousValue ,
currentValue : nextValue ,
currentValue : nextValue ,
status : subPropertyStatus ,
status : subPropertyStatus ,
. . . ( subPropertyStatus !== STATUS . EQUAL && { subPropertiesDiff } ) ,
. . . ( subPropertyStatus !== OBJECT_STATUS . EQUAL && {
diff : subPropertiesDiff ,
} ) ,
} ) ;
} ) ;
}
}
return diff . push ( {
return diff . push ( {
@ -299,7 +280,7 @@ export function getObjectDiff(
property : deletedProperty.property ,
property : deletedProperty.property ,
previousValue : deletedProperty.value ,
previousValue : deletedProperty.value ,
currentValue : undefined ,
currentValue : undefined ,
status : STATUS.DELETED ,
status : OBJECT_ STATUS.DELETED,
} ) ;
} ) ;
} ) ;
} ) ;
}
}