// ets_tracing: off /** * An `Optional` is an optic used to zoom inside a product. Unlike the `Lens`, the element that the `Optional` focuses * on may not exist. * * `Optional`s have two type parameters generally called `S` and `A`: `Optional` where `S` represents the product * and `A` an optional element inside of `S`. * * Laws: * * 1. getOption(s).fold(() => s, a => set(a)(s)) = s * 2. getOption(set(a)(s)) = getOption(s).map(_ => a) * 3. set(a)(set(a)(s)) = set(a)(s) */ import type { Either } from "@effect-ts/core/Either" import type { Predicate, Refinement } from "@effect-ts/core/Function" import { constant, flow, pipe } from "@effect-ts/core/Function" import * as O from "@effect-ts/core/Option" import type { URI } from "@effect-ts/core/Prelude" import * as P from "@effect-ts/core/Prelude" import type { HashMap } from "@effect-ts/system/Collections/Immutable/HashMap" import * as _ from "../Internal/index.js" import { Optional } from "../Internal/index.js" import type { Traversal } from "../Traversal/index.js" // ------------------------------------------------------------------------------------- // model // ------------------------------------------------------------------------------------- import Option = O.Option export { Optional } // ------------------------------------------------------------------------------------- // constructors // ------------------------------------------------------------------------------------- export const id = (): Optional => new Optional({ getOption: O.some, set: constant }) // ------------------------------------------------------------------------------------- // converters // ------------------------------------------------------------------------------------- /** * View a `Optional` as a `Traversal` */ export const asTraversal: (sa: Optional) => Traversal = _.optionalAsTraversal // ------------------------------------------------------------------------------------- // compositions // ------------------------------------------------------------------------------------- /** * Compose a `Optional` with a `Optional` */ export const compose: ( ab: Optional ) => (sa: Optional) => Optional = _.optionalComposeOptional // ------------------------------------------------------------------------------------- // combinators // ------------------------------------------------------------------------------------- export const modifyOption: ( f: (a: A) => A ) => (optional: Optional) => (s: S) => Option = _.optionalModifyOption export const modify: ( f: (a: A) => A ) => (optional: Optional) => (s: S) => S = _.optionalModify /** * Return an `Optional` from a `Optional` focused on a nullable value */ export const fromNullable: (sa: Optional) => Optional> = compose(_.prismAsOptional(_.prismFromNullable())) export function filter( refinement: Refinement ): (sa: Optional) => Optional export function filter( predicate: Predicate ): (sa: Optional) => Optional export function filter( predicate: Predicate ): (sa: Optional) => Optional { return compose(_.prismAsOptional(_.prismFromPredicate(predicate))) } /** * Return a `Optional` from a `Optional` and a prop */ export const prop = ( prop: P ): ((sa: Optional) => Optional) => compose(pipe(_.lensId(), _.lensProp(prop), _.lensAsOptional)) /** * Return a `Optional` from a `Optional` and a list of props */ export const props = ( ...props: [P, P, ...Array

] ): ((sa: Optional) => Optional) => compose(pipe(_.lensId(), _.lensProps(...props), _.lensAsOptional)) /** * Return a `Optional` from a `Optional` and a component */ export const component = , P extends keyof A>( prop: P ): ((sa: Optional) => Optional) => compose(pipe(_.lensId(), _.lensComponent(prop), _.lensAsOptional)) /** * Return a `Optional` from a `Optional` focused on a `ReadonlyArray` */ export const index = (i: number) => (sa: Optional>): Optional => pipe(sa, _.optionalComposeOptional(_.indexArray().index(i))) /** * Return a `Optional` from a `Optional` focused on a `ReadonlyRecord` and a key */ export const keyInRecord = (key: string) => (sa: Optional>>): Optional => pipe(sa, _.optionalComposeOptional(_.indexRecord().index(key))) /** * Return a `Optional` from a `Optional` focused on a `ReadonlyRecord` and a required key */ export const atKeyInRecord = (key: string) => (sa: Optional>>): Optional> => pipe(sa, compose(_.lensAsOptional(_.atRecord().at(key)))) /** * Return a `Optional` from a `Optional` focused on a `HashMap` and a key */ export const keyInHashMap = (key: K) => (sa: Optional>>): Optional => pipe(sa, _.optionalComposeOptional(_.indexHashMap().index(key))) /** * Return a `Optional` from a `Optional` focused on a `HashMap` and a required key */ export const atKeyInHashMap = (key: K) => (sa: Optional>>): Optional> => pipe(sa, compose(_.lensAsOptional(_.atHashMap().at(key)))) /** * Return a `Optional` from a `Optional` focused on the `Some` of a `Option` type */ export const some: (soa: Optional>) => Optional = compose( _.prismAsOptional(_.prismSome()) ) /** * Return a `Optional` from a `Optional` focused on the `Right` of a `Either` type */ export const right: (sea: Optional>) => Optional = compose(_.prismAsOptional(_.prismRight())) /** * Return a `Optional` from a `Optional` focused on the `Left` of a `Either` type */ export const left: (sea: Optional>) => Optional = compose(_.prismAsOptional(_.prismLeft())) /** * Return a `Traversal` from a `Optional` focused on a `ForEach` */ export function forEach( T: P.ForEach ): ( sta: Optional> ) => Traversal { return flow(asTraversal, _.traversalComposeTraversal(_.fromForEach(T)())) } export const find: ( predicate: Predicate ) => (sa: Optional>) => Optional = flow(_.find, compose) // ------------------------------------------------------------------------------------- // pipeables // ------------------------------------------------------------------------------------- export const imap: ( f: (a: A) => B, g: (b: B) => A ) => (fa: Optional) => Optional = (f, g) => (ea) => new Optional({ getOption: flow(ea.getOption, O.map(f)), set: flow(g, ea.set) }) // ------------------------------------------------------------------------------------- // instances // ------------------------------------------------------------------------------------- export const OptionalURI = "monocle/Optional" export type OptionalURI = typeof OptionalURI declare module "@effect-ts/core/Prelude/HKT" { export interface URItoKind { [OptionalURI]: Optional } } export const Category = P.instance]>>({ compose, id }) export const Invariant = P.instance]>>({ invmap: ({ f, g }) => ({ f: imap(f, g), g: imap(g, f) }) })