/** * @since 2.0.0 */ import type { Chunk } from "./Chunk.js" import type { Context } from "./Context.js" import type { Either } from "./Either.js" import type { Equal } from "./Equal.js" import * as Dual from "./Function.js" import type { HashMap } from "./HashMap.js" import type { HashSet } from "./HashSet.js" import * as internal from "./internal/differ.js" import * as ChunkPatch from "./internal/differ/chunkPatch.js" import * as ContextPatch from "./internal/differ/contextPatch.js" import * as HashMapPatch from "./internal/differ/hashMapPatch.js" import * as HashSetPatch from "./internal/differ/hashSetPatch.js" import * as OrPatch from "./internal/differ/orPatch.js" import * as ReadonlyArrayPatch from "./internal/differ/readonlyArrayPatch.js" import type { Pipeable } from "./Pipeable.js" import type * as Types from "./Types.js" /** * @since 2.0.0 * @category symbol */ export const TypeId: unique symbol = internal.DifferTypeId as TypeId /** * @since 2.0.0 * @category symbol */ export type TypeId = typeof TypeId /** * A `Differ` knows how to compare an old value and new value of * type `Value` to produce a patch of type `Patch` that describes the * differences between those values. A `Differ` also knows how to apply a patch * to an old value to produce a new value that represents the old value updated * with the changes described by the patch. * * A `Differ` can be used to construct a `FiberRef` supporting compositional * updates using the `FiberRef.makePatch` constructor. * * The `Differ` companion object contains constructors for `Differ` values for * common data types such as `Chunk`, `HashMap`, and `HashSet``. In addition, * `Differ`values can be transformed using the `transform` operator and combined * using the `orElseEither` and `zip` operators. This allows creating `Differ` * values for arbitrarily complex data types compositionally. * * @since 2.0.0 * @category models */ export interface Differ extends Pipeable { readonly [TypeId]: { readonly _V: Types.Invariant readonly _P: Types.Invariant } readonly empty: Patch diff(oldValue: Value, newValue: Value): Patch combine(first: Patch, second: Patch): Patch patch(patch: Patch, oldValue: Value): Value } const ChunkPatchTypeId: unique symbol = ChunkPatch.ChunkPatchTypeId as Differ.Chunk.TypeId const ContextPatchTypeId: unique symbol = ContextPatch.ContextPatchTypeId as Differ.Context.TypeId const HashMapPatchTypeId: unique symbol = HashMapPatch.HashMapPatchTypeId as Differ.HashMap.TypeId const HashSetPatchTypeId: unique symbol = HashSetPatch.HashSetPatchTypeId as Differ.HashSet.TypeId const OrPatchTypeId: unique symbol = OrPatch.OrPatchTypeId as Differ.Or.TypeId const ReadonlyArrayPatchTypeId: unique symbol = ReadonlyArrayPatch .ReadonlyArrayPatchTypeId as Differ.ReadonlyArray.TypeId /** * @since 2.0.0 */ export declare namespace Differ { /** * @since 2.0.0 */ export namespace Context { /** * @since 2.0.0 * @category symbol */ export type TypeId = typeof ContextPatchTypeId /** * A `Patch` describes an update that transforms a `Env` * to a `Env` as a data structure. This allows combining updates to * different services in the environment in a compositional way. * * @since 2.0.0 * @category models */ export interface Patch extends Equal { readonly [ContextPatchTypeId]: { readonly _Input: Types.Contravariant readonly _Output: Types.Covariant } } } /** * @since 2.0.0 */ export namespace Chunk { /** * @since 2.0.0 * @category symbol */ export type TypeId = typeof ChunkPatchTypeId /** * A patch which describes updates to a chunk of values. * * @since 2.0.0 * @category models */ export interface Patch extends Equal { readonly [ChunkPatchTypeId]: { readonly _Value: Types.Invariant readonly _Patch: Types.Invariant } } } /** * @since 2.0.0 */ export namespace HashMap { /** * @since 2.0.0 * @category symbol */ export type TypeId = typeof HashMapPatchTypeId /** * A patch which describes updates to a map of keys and values. * * @since 2.0.0 * @category models */ export interface Patch extends Equal { readonly [HashMapPatchTypeId]: { readonly _Key: Types.Invariant readonly _Value: Types.Invariant readonly _Patch: Types.Invariant } } } /** * @since 2.0.0 */ export namespace HashSet { /** * @since 2.0.0 * @category symbol */ export type TypeId = typeof HashSetPatchTypeId /** * A patch which describes updates to a set of values. * * @since 2.0.0 * @category models */ export interface Patch extends Equal { readonly [HashSetPatchTypeId]: { readonly _Value: Types.Invariant } } } /** * @since 2.0.0 */ export namespace Or { /** * @since 2.0.0 * @category symbol */ export type TypeId = typeof OrPatchTypeId /** * A patch which describes updates to either one value or another. * * @since 2.0.0 * @category models */ export interface Patch extends Equal { readonly [OrPatchTypeId]: { readonly _Value: Types.Invariant readonly _Value2: Types.Invariant readonly _Patch: Types.Invariant readonly _Patch2: Types.Invariant } } } /** * @since 2.0.0 */ export namespace ReadonlyArray { /** * @since 2.0.0 * @category symbol */ export type TypeId = typeof ReadonlyArrayPatchTypeId /** * A patch which describes updates to a ReadonlyArray of values. * * @since 2.0.0 * @category models */ export interface Patch extends Equal { readonly [ReadonlyArrayPatchTypeId]: { readonly _Value: Types.Invariant readonly _Patch: Types.Invariant } } } } /** * An empty patch that describes no changes. * * @since 2.0.0 * @category patch */ export const empty: (self: Differ) => Patch = ( self ) => self.empty /** * @since 2.0.0 * @category patch */ export const diff: { /** * @since 2.0.0 * @category patch */ (oldValue: Value, newValue: Value): ( self: Differ ) => Patch /** * @since 2.0.0 * @category patch */ (self: Differ, oldValue: Value, newValue: Value): Patch } = Dual.dual( 3, ( self: Differ, oldValue: Value, newValue: Value ): Patch => self.diff(oldValue, newValue) ) /** * Combines two patches to produce a new patch that describes the updates of * the first patch and then the updates of the second patch. The combine * operation should be associative. In addition, if the combine operation is * commutative then joining multiple fibers concurrently will result in * deterministic `FiberRef` values. * * @since 2.0.0 * @category patch */ export const combine: { /** * Combines two patches to produce a new patch that describes the updates of * the first patch and then the updates of the second patch. The combine * operation should be associative. In addition, if the combine operation is * commutative then joining multiple fibers concurrently will result in * deterministic `FiberRef` values. * * @since 2.0.0 * @category patch */ (first: Patch, second: Patch): ( self: Differ ) => Patch /** * Combines two patches to produce a new patch that describes the updates of * the first patch and then the updates of the second patch. The combine * operation should be associative. In addition, if the combine operation is * commutative then joining multiple fibers concurrently will result in * deterministic `FiberRef` values. * * @since 2.0.0 * @category patch */ (self: Differ, first: Patch, second: Patch): Patch } = Dual.dual( 3, ( self: Differ, first: Patch, second: Patch ): Patch => self.combine(first, second) ) /** * Applies a patch to an old value to produce a new value that is equal to the * old value with the updates described by the patch. * * @since 2.0.0 * @category patch */ export const patch: { /** * Applies a patch to an old value to produce a new value that is equal to the * old value with the updates described by the patch. * * @since 2.0.0 * @category patch */ (patch: Patch, oldValue: Value): ( self: Differ ) => Value /** * Applies a patch to an old value to produce a new value that is equal to the * old value with the updates described by the patch. * * @since 2.0.0 * @category patch */ (self: Differ, patch: Patch, oldValue: Value): Value } = Dual.dual( 3, ( self: Differ, patch: Patch, oldValue: Value ): Value => self.patch(patch, oldValue) ) /** * Constructs a new `Differ`. * * @since 2.0.0 * @category constructors */ export const make: (params: { readonly empty: Patch readonly diff: (oldValue: Value, newValue: Value) => Patch readonly combine: (first: Patch, second: Patch) => Patch readonly patch: (patch: Patch, oldValue: Value) => Value }) => Differ = internal.make /** * Constructs a differ that knows how to diff `Env` values. * * @since 2.0.0 * @category constructors */ export const environment: () => Differ< Context, Differ.Context.Patch > = internal.environment /** * Constructs a differ that knows how to diff a `Chunk` of values given a * differ that knows how to diff the values. * * @since 2.0.0 * @category constructors */ export const chunk: ( differ: Differ ) => Differ, Differ.Chunk.Patch> = internal.chunk /** * Constructs a differ that knows how to diff a `HashMap` of keys and values given * a differ that knows how to diff the values. * * @since 2.0.0 * @category constructors */ export const hashMap: ( differ: Differ ) => Differ, Differ.HashMap.Patch> = internal.hashMap /** * Constructs a differ that knows how to diff a `HashSet` of values. * * @since 2.0.0 * @category constructors */ export const hashSet: () => Differ< HashSet, Differ.HashSet.Patch > = internal.hashSet /** * Combines this differ and the specified differ to produce a differ that * knows how to diff the sum of their values. * * @since 2.0.0 */ export const orElseEither: { /** * Combines this differ and the specified differ to produce a differ that * knows how to diff the sum of their values. * * @since 2.0.0 */ (that: Differ): ( self: Differ ) => Differ< Either, Differ.Or.Patch > /** * Combines this differ and the specified differ to produce a differ that * knows how to diff the sum of their values. * * @since 2.0.0 */ (self: Differ, that: Differ): Differ< Either, Differ.Or.Patch > } = internal.orElseEither /** * Constructs a differ that knows how to diff a `ReadonlyArray` of values. * * @since 2.0.0 * @category constructors */ export const readonlyArray: ( differ: Differ ) => Differ, Differ.ReadonlyArray.Patch> = internal.readonlyArray /** * Transforms the type of values that this differ knows how to differ using * the specified functions that map the new and old value types to each other. * * @since 2.0.0 */ export const transform: { /** * Transforms the type of values that this differ knows how to differ using * the specified functions that map the new and old value types to each other. * * @since 2.0.0 */ ( options: { readonly toNew: (value: Value) => Value2 readonly toOld: (value: Value2) => Value } ): (self: Differ) => Differ /** * Transforms the type of values that this differ knows how to differ using * the specified functions that map the new and old value types to each other. * * @since 2.0.0 */ ( self: Differ, options: { readonly toNew: (value: Value) => Value2 readonly toOld: (value: Value2) => Value } ): Differ } = internal.transform /** * Constructs a differ that just diffs two values by returning a function that * sets the value to the new value. This differ does not support combining * multiple updates to the value compositionally and should only be used when * there is no compositional way to update them. * * @since 2.0.0 */ export const update: () => Differ A> = internal.update /** * A variant of `update` that allows specifying the function that will be used * to combine old values with new values. * * @since 2.0.0 */ export const updateWith: (f: (x: A, y: A) => A) => Differ A> = internal.updateWith /** * Combines this differ and the specified differ to produce a new differ that * knows how to diff the product of their values. * * @since 2.0.0 */ export const zip: { /** * Combines this differ and the specified differ to produce a new differ that * knows how to diff the product of their values. * * @since 2.0.0 */ (that: Differ): ( self: Differ ) => Differ< readonly [Value, Value2], // readonly because invariant readonly [Patch, Patch2] // readonly because invariant > /** * Combines this differ and the specified differ to produce a new differ that * knows how to diff the product of their values. * * @since 2.0.0 */ (self: Differ, that: Differ): Differ< readonly [Value, Value2], // readonly because invariant readonly [Patch, Patch2] // readonly because invariant > } = internal.zip