UNPKG

@sanity/diff

Version:

Generates diffs between documents and primitive types

357 lines • 11.5 kB
/** * Options available for doing diffs. Currently no options are defined. * * @public */ type DiffOptions = Record<string, never>; /** * The recognized diff value types * * @public */ type ValueType = 'array' | 'boolean' | 'null' | 'number' | 'object' | 'string' | 'undefined'; /** * An "input" holds the _type_ of the value, the actual value, an optional annotation, * along with potential helper methods and properties, which vary dependending on the type * * @public */ type Input<T> = NumberInput<T> | BooleanInput<T> | StringInput<T> | NullInput<T> | ObjectInput<T> | ArrayInput<T>; /** * Shared properties for all input types * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface BaseInput<A> { annotation: A; } /** * Input type for strings, which supports slicing parts of the string while maintaining the * annotation of the parent. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface StringInput<A> extends BaseInput<A> { type: 'string'; value: string; sliceAnnotation(start: number, end: number): { text: string; annotation: A; }[]; } /** * Input type for numbers. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface NumberInput<A> extends BaseInput<A> { type: 'number'; value: number; } /** * Input type for booleans. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface BooleanInput<A> extends BaseInput<A> { type: 'boolean'; value: boolean; } /** * Input type for `null` values. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface NullInput<A> extends BaseInput<A> { type: 'null'; value: null; } /** * Input type for object values. Caches the available keys, and allows retrieval of properties, * while automatically wrapping the retrieved property in a typed input container. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface ObjectInput<A> extends BaseInput<A> { type: 'object'; /** * The actual object value */ value: Record<string, unknown>; /** * The keys of the object */ keys: string[]; /** * Retrieve the property with the given `key`, automatically wrapping it in an input container. * * @param key - The key of the property you want to retrieve. * @returns Typed input container, or `undefined` if the property does not exist */ get(key: string): Input<A> | undefined; } /** * Input type for array values. Helper functions are available for getting the item and/or * annotation at a given index. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface ArrayInput<A> extends BaseInput<A> { type: 'array'; /** * The actual array value */ value: unknown[]; /** * The length of the array */ length: number; /** * Retrieve the value at the given `index`, automatically wrapping it in an input container. * * @param index - The index of the item to retrieve * @returns Typed input container, or `undefined` if the item does not exist */ at(index: number): Input<A>; /** * Retrieve the _annotation_ for an item at the given index * * @param index - The index of the item to fetch the annotation for * @returns The annotation at the given index, or `undefined` if the item does not exist */ annotationAt(index: number): A; } /** * Diff for something that has been added - eg a property in an object, * an item in an array, a segment of a string or similar. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @typeParam V - Value. The type of the destination (eg `after` or `to`) value. * @public */ interface AddedDiff<A, V> { action: 'added'; isChanged: true; fromValue: null | undefined; toValue: V; annotation: A; } /** * Diff for something that has been removed - eg a property in an object, * an item in an array, a segment of a string or similar. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @typeParam V - Value. The type of the source (eg `before` or `from`) value. * @public */ interface RemovedDiff<A, V> { action: 'removed'; isChanged: true; fromValue: V; toValue: null | undefined; annotation: A; } /** * Diff for something that has changed - eg it was not added or removed, but the * value has changed "in place". Note that {@link TypeChangeDiff} is used for values that change * their _type_, thus the `V` type parameter represents both the source and the destination value * in this type. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @typeParam V - Value. The type of the value. * @public */ interface ChangedDiff<A, V> { action: 'changed'; isChanged: true; fromValue: V; toValue: V; annotation: A; } /** * Diff (or lack thereof, in this case) for a value that has _not_ changed. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @typeParam V - Value. The type of the destination (eg `after`) value. * @public */ interface UnchangedDiff<A, V> { action: 'unchanged'; isChanged: false; fromValue: V; toValue: V; } /** * Diff with all the possible diff types. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @typeParam V - Value. Type of the value repesented in the diff. * @public */ type FullDiff<A, V> = AddedDiff<A, V> | RemovedDiff<A, V> | ChangedDiff<A, V> | UnchangedDiff<A, V>; /** * Diff of a string. Holds an additional array of string _segments_, * indicating which portions of the string is changed/unchanged. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ type StringDiff<A> = FullDiff<A, string> & { type: 'string'; segments: StringDiffSegment<A>[]; }; /** * Diff of a number. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ type NumberDiff<A> = FullDiff<A, number> & { type: 'number'; }; /** * Diff of a boolean. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ type BooleanDiff<A> = FullDiff<A, boolean> & { type: 'boolean'; }; /** * Diff for a value that has changed from one type to another. * For example, an object property going from `null` to `string`. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface TypeChangeDiff<A> { type: 'typeChange'; action: 'changed'; isChanged: true; fromType: string; fromValue: unknown; fromDiff: Diff<A> & { action: 'removed'; }; toType: string; toValue: unknown; toDiff: Diff<A> & { action: 'added'; }; annotation: A; } /** * Diff for an object value. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @typeParam T - Value type. * @public */ type ObjectDiff<A, T extends object = Record<string, any>> = FullDiff<A, T> & { type: 'object'; fields: Record<keyof T, Diff<A>>; }; /** * Diff for an array value. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @typeParam V - Item value type. * @public */ type ArrayDiff<A, V = unknown> = FullDiff<A, V[]> & { type: 'array'; items: ItemDiff<A>[]; }; /** * Diff for a `null` value. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ type NullDiff<A> = FullDiff<A, null> & { type: 'null'; }; /** * Diff for any value type. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ type Diff<A> = NullDiff<A> | StringDiff<A> | NumberDiff<A> | BooleanDiff<A> | ObjectDiff<A> | ArrayDiff<A> | TypeChangeDiff<A>; /** * Diff of a string segment (eg a portion/slice), and whether or not it was changed or unchanged. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ type StringDiffSegment<A> = StringSegmentChanged<A> | StringSegmentUnchanged; /** * Diff of a string segment that has changed. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface StringSegmentChanged<A> { type: 'stringSegment'; action: 'added' | 'removed'; text: string; annotation: A; } /** * Diff of a string segment that is unchanged. * * @public */ interface StringSegmentUnchanged { type: 'stringSegment'; action: 'unchanged'; text: string; } /** * Diff of an item in an array, representing whether or not it has moved within the array, * and if so, which index it was moved from/to. * * If not moved, `fromIndex` and `toIndex` will have the same value. * If the item was added, `fromIndex` will be `undefined`. * If the item was removed, `toIndex` will be `undefined`. * * @typeParam A - Annotation. Timestamps, author and similar info is attached by Sanity, but anything is allowed. * @public */ interface ItemDiff<A> { fromIndex: number | undefined; toIndex: number | undefined; hasMoved: boolean; diff: Diff<A>; annotation: A; } /** * 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 */ declare function diffInput<A>(fromInput: Input<A>, toInput: Input<A>, options?: DiffOptions): Diff<A>; /** * Takes an input (any JSON-serializable value) and an annotation, and generates an input * object for it, to be used with {@link diffInput | the diffInput() method} and others. * * @param input - The value to wrap in an input object * @param annotation - Annotation attached to the input - will be bound to generated diffs * @returns A input object * @throws if `input` is not a JSON-serializable type * @public */ declare function wrap<A>(input: unknown, annotation: A): Input<A>; export { AddedDiff, ArrayDiff, ArrayInput, BaseInput, BooleanDiff, BooleanInput, ChangedDiff, Diff, DiffOptions, FullDiff, Input, ItemDiff, NullDiff, NullInput, NumberDiff, NumberInput, ObjectDiff, ObjectInput, RemovedDiff, StringDiff, StringDiffSegment, StringInput, StringSegmentChanged, StringSegmentUnchanged, TypeChangeDiff, UnchangedDiff, ValueType, diffInput, wrap };