@sanity/diff
Version:
Generates diffs between documents and primitive types
114 lines (98 loc) • 2.78 kB
text/typescript
import {replaceProperty} from '../helpers'
import {type DiffOptions, type ObjectDiff, type ObjectInput} from '../types'
import {addedInput, diffInput, removedInput} from './diffInput'
const ignoredFields = new Set(['_id', '_type', '_createdAt', '_updatedAt', '_rev', '_weak'])
export function diffObject<A>(
fromInput: ObjectInput<A>,
toInput: ObjectInput<A>,
options: DiffOptions,
): ObjectDiff<A> {
const fields: ObjectDiff<A>['fields'] = {}
let isChanged = false
for (const key of fromInput.keys) {
if (ignoredFields.has(key)) continue
const fromField = fromInput.get(key)!
const toField = toInput.get(key)
if (toField) {
const fieldDiff = diffInput(fromField, toField, options)
fields[key] = fieldDiff
if (fieldDiff.isChanged) isChanged = true
} else {
fields[key] = removedInput(fromField, undefined, options)
isChanged = true
}
}
for (const key of toInput.keys) {
if (ignoredFields.has(key)) continue
// Already handled above
if (fromInput.get(key)) continue
const toField = toInput.get(key)!
fields[key] = addedInput(toField, undefined, options)
isChanged = true
}
const fromValue = fromInput.value
const toValue = toInput.value
if (!isChanged) {
return {
type: 'object',
action: 'unchanged',
isChanged: false,
fromValue,
toValue,
fields,
}
}
return {
type: 'object',
action: 'changed',
isChanged: true,
fromValue,
toValue,
fields,
annotation: toInput.annotation,
}
}
export function removedObject<A>(
input: ObjectInput<A>,
toValue: null | undefined,
options: DiffOptions,
): ObjectDiff<A> & {action: 'removed'} {
return {
type: 'object',
action: 'removed',
isChanged: true,
fromValue: input.value,
toValue,
annotation: input.annotation,
get fields(): ObjectDiff<A>['fields'] {
const fields: ObjectDiff<A>['fields'] = {}
for (const key of input.keys) {
const value = input.get(key)!
fields[key] = removedInput(value, undefined, options)
}
return replaceProperty(this, 'fields', fields)
},
}
}
export function addedObject<A>(
input: ObjectInput<A>,
fromValue: null | undefined,
options: DiffOptions,
): ObjectDiff<A> & {action: 'added'} {
return {
type: 'object',
action: 'added',
isChanged: true,
fromValue,
toValue: input.value,
annotation: input.annotation,
get fields(): ObjectDiff<A>['fields'] {
const fields: ObjectDiff<A>['fields'] = {}
for (const key of input.keys) {
const value = input.get(key)!
fields[key] = addedInput(value, undefined, options)
}
return replaceProperty(this, 'fields', fields)
},
}
}