UNPKG

@sanity/diff

Version:

Generates diffs between documents and primitive types

163 lines (155 loc) 4.41 kB
import { type ArrayInput, type BooleanInput, type Diff, type DiffOptions, type Input, type NumberInput, type ObjectInput, type StringInput, } from '../types' import {addedArray, diffArray, removedArray} from './diffArray' import {addedObject, diffObject, removedObject} from './diffObject' import {diffBoolean, diffNumber} from './diffSimple' import {addedString, diffString, removedString} from './diffString' import {diffTypeChange} from './diffTypeChange' /** * Takes a `from` and `to` input and calulates a diff between the two * * @param fromInput - The source (`from`) input - use {@link wrap | the wrap() method} to generate an "input" * @param toInput - The destination (`to`) input - use {@link wrap | the wrap() method} to generate an "input" * @param options - Options for the diffing process - currently no options are defined * @returns A diff object representing the change * @public */ export function diffInput<A>( fromInput: Input<A>, toInput: Input<A>, options: DiffOptions = {}, ): Diff<A> { if (fromInput.type !== toInput.type) { if (fromInput.type === 'null') { return addedInput(toInput, null, options) } if (toInput.type === 'null') { return removedInput(fromInput, null, options) } return diffTypeChange(fromInput, toInput, options) } return diffWithType(fromInput.type, fromInput, toInput, options) } function diffWithType<A>( type: Input<A>['type'], fromInput: Input<A>, toInput: Input<A>, options: DiffOptions, ): Diff<A> { switch (type) { case 'null': return { type: 'null', action: 'unchanged', isChanged: false, toValue: null, fromValue: null, } case 'boolean': return diffBoolean(fromInput as BooleanInput<A>, toInput as BooleanInput<A>, options) case 'number': return diffNumber(fromInput as NumberInput<A>, toInput as NumberInput<A>, options) case 'string': return diffString(fromInput as StringInput<A>, toInput as StringInput<A>, options) case 'array': return diffArray(fromInput as ArrayInput<A>, toInput as ArrayInput<A>, options) case 'object': return diffObject(fromInput as ObjectInput<A>, toInput as ObjectInput<A>, options) default: throw new Error(`Unhandled diff type "${type}"`) } } export function removedInput<A>( input: Input<A>, toValue: null | undefined, options: DiffOptions, ): Diff<A> & {action: 'removed'} { switch (input.type) { case 'null': return { type: 'null', action: 'removed', isChanged: true, fromValue: null, toValue, annotation: input.annotation, } case 'boolean': return { type: 'boolean', action: 'removed', isChanged: true, fromValue: input.value, toValue, annotation: input.annotation, } case 'number': return { type: 'number', action: 'removed', isChanged: true, fromValue: input.value, toValue, annotation: input.annotation, } case 'string': return removedString(input, toValue, options) case 'array': return removedArray(input, toValue, options) case 'object': return removedObject(input, toValue, options) default: throw new Error('Unhandled diff type') } } export function addedInput<A>( input: Input<A>, fromValue: null | undefined, options: DiffOptions, ): Diff<A> & {action: 'added'} { switch (input.type) { case 'null': return { type: 'null', action: 'added', isChanged: true, fromValue, toValue: null, annotation: input.annotation, } case 'boolean': return { type: 'boolean', action: 'added', isChanged: true, fromValue, toValue: input.value, annotation: input.annotation, } case 'number': return { type: 'number', action: 'added', isChanged: true, fromValue, toValue: input.value, annotation: input.annotation, } case 'string': return addedString(input, fromValue, options) case 'array': return addedArray(input, fromValue, options) case 'object': return addedObject(input, fromValue, options) default: throw new Error('Unhandled diff type') } }