module import Result from './result.js' ; import { curry1 , isVoid } from './-private/utils.js' ; import * as Toolbelt from './toolbelt.js' ; /**
  Discriminant for the {@linkcode Just} and {@linkcode Nothing} type instances.

  You can use the discriminant via the `variant` property of {@linkcode Maybe}¿
  instances if you need to match explicitly on it.
 */ export const Variant = { Just : 'Just' , Nothing : 'Nothing' , } as const ; export type Variant = keyof typeof Variant ; export interface JustJSON < T > { variant : 'Just' ; value : T ; } export interface NothingJSON { variant : 'Nothing' ; } export type MaybeJSON < T > = JustJSON < T > | NothingJSON ; type Repr < T > = [ tag : 'Just' , value : T ] | [ tag : 'Nothing' ] ; private let NOTHING ; class MaybeImpl < T > { private repr : Repr < T > ; constructor ( value ? ) { if ( isVoid ( value ) ) { this . repr = [ Variant . Nothing ] ; if ( ! NOTHING ) { NOTHING = this as Maybe < any > as Nothing < any > ; } return NOTHING as Maybe < any > as this ; } else { this . repr = [ Variant . Just , value ] ; } } typeparam param value static of < T > ( value ) { return new MaybeImpl ( value ) as Maybe < T > ; } typeparam param value returns throws static just < T > ( value ? ) { if ( isVoid ( value ) ) { throw new Error ( `attempted to call "just" with ${ value }` ) ; } return new MaybeImpl < T > ( value ) as Maybe < T > ; } typeparam returns static nothing < T > ( _ ? ) { return new MaybeImpl ( ) as Nothing < T > ; } /** Distinguish between the `Just` and `Nothing`  Variant .  get variant ( ) : Variant { return this . repr [ 0 ] ; } warning get value ( ) : T { if ( this . repr [ 0 ] === Variant . Nothing ) { throw new Error ( 'Cannot get the value of `Nothing`' ) ; } return this . repr [ 1 ] ; } /** Is the {@linkcode Maybe} a {@linkcode Just}? */ get isJust ( ) : boolean { return this . repr [ 0 ] === Variant . Just ; } /** Is the {@linkcode Maybe} a {@linkcode Nothing}? */ get isNothing ( ) : boolean { return this . repr [ 0 ] === Variant . Nothing ; } /** Method variant for {@linkcode map} */ map < U > ( this , mapFn ) { return map ( mapFn , this ) ; } /** Method variant for  mapOr mapOr < U > ( this , orU , mapFn ) { return mapOr ( orU , mapFn , this ) ; } /** Method variant for {@linkcode mapOrElse} */ mapOrElse < U > ( this , orElseFn , mapFn ) { return mapOrElse ( orElseFn , mapFn , this ) ; } /** Method variant for {@linkcode match} */ match < U > ( this , matcher ) { return match ( matcher , this ) ; } /** Method variant for {@linkcode or} */ or ( this , mOr ) { return or ( mOr , this ) ; } /** Method variant for {@linkcode orElse} */ orElse ( this , orElseFn ) { return orElse ( orElseFn , this ) ; } /** Method variant for {@linkcode and} */ and < U > ( this , mAnd ) { return and ( mAnd , this ) ; } /** Method variant for {@linkcode andThen} */ andThen < U > ( this , andThenFn ) { return andThen ( andThenFn , this ) ; } /** Method variant for {@linkcode unwrapOr} */ unwrapOr < U > ( this , defaultValue ) { return unwrapOr ( defaultValue , this ) ; } /** Method variant for {@linkcode unwrapOrElse} */ unwrapOrElse < U > ( this , elseFn ) { return unwrapOrElse ( elseFn , this ) ; } deprecated toOkOrErr < E > ( this , error ) { return Toolbelt . toOkOrErr ( error , this ) ; } deprecated toOkOrElseErr < E > ( this , elseFn ) { return Toolbelt . toOkOrElseErr ( elseFn , this ) ; } /** Method variant for {@linkcode toString} */ toString ( this ) { return toString ( this ) ; } /** Method variant for {@linkcode toJSON} */ toJSON ( this ) { return toJSON ( this ) ; } /** Method variant for {@linkcode equals} */ equals ( this , comparison ) { return equals ( comparison , this ) ; } /** Method variant for {@linkcode ap} */ ap < A , B > ( this , val ) { return ap ( this , val ) ; } /**
      Method variant for {@linkcode get}
  
      If you have a `Maybe` of an object type, you can do `thatMaybe.get('a key')`
      to look up the next layer down in the object.
  
      ```ts
      type DeepOptionalType = {
        something?: {
          with?: {
            deeperKeys?: string;
          }
        }
      };
  
      const fullySet: DeepType = {
        something: {
          with: {
            deeperKeys: 'like this'
          }
        }
      };
  
      const deepJust = Maybe.of(fullySet)
        .get('something')
        .get('with')
        .get('deeperKeys');
  
      console.log(deepJust); // Just('like this');
  
      const partiallyUnset: DeepType = { something: { } };
  
      const deepEmpty = Maybe.of(partiallyUnset)
        .get('something')
        .get('with')
        .get('deeperKeys');
  
      console.log(deepEmpty); // Nothing
      ```
     */ get < K extends keyof T > ( this , key ) { return get ( key , this ) ; } } typeparam export interface Just < T > extends MaybeImpl < T > { /** `Just` is always {@linkcode Variant.Just}. */ variant : 'Just' ; /** The wrapped value. */ value : T ; isJust : true ; isNothing : false ; } typeparam export interface Nothing < T > extends Pick < MaybeImpl < T > , Exclude < keyof MaybeImpl < T > , 'value' > > { /** `Nothing` is always {@linkcode Variant.Nothing}. */ readonly variant : 'Nothing' ; isJust : false ; isNothing : true ; } typeparam param value returns throws export const just = MaybeImpl . just ; typeparam returns export const nothing = MaybeImpl . nothing ; typeparam param value export const of = MaybeImpl . of ; typeparam typeparam param mapFn param maybe returns export function map < T , U > ( mapFn ) ; export function map < T , U > ( mapFn , maybe ) ; export function map < T , U > ( mapFn , maybe ? ) { const op = ( m ) => ( m . isJust ? just ( mapFn ( m . value ) ) : nothing < U > ( ) ) ; return curry1 ( op , maybe ) ; } typeparam typeparam param orU param mapFn param maybe export function mapOr < T , U > ( orU , mapFn , maybe ) ; export function mapOr < T , U > ( orU , mapFn ) ; export function mapOr < T , U > ( orU ) ; export function mapOr < T , U > ( orU , mapFn ? , maybe ? ) { function fullOp ( fn , m ) { return m . isJust ? fn ( m . value ) : orU ; } function partialOp ( fn ) ; function partialOp ( fn , curriedMaybe ) ; function partialOp ( fn , curriedMaybe ? ) { return curriedMaybe !== undefined ? fullOp ( fn , curriedMaybe ) : ( extraCurriedMaybe ) => fullOp ( fn , extraCurriedMaybe ) ; } return mapFn === undefined ? partialOp : maybe === undefined ? partialOp ( mapFn ) : partialOp ( mapFn , maybe ) ; } typeparam typeparam param orElseFn param mapFn param maybe export function mapOrElse < T , U > ( orElseFn , mapFn , maybe ) ; export function mapOrElse < T , U > ( orElseFn , mapFn ) ; export function mapOrElse < T , U > ( orElseFn ) ; export function mapOrElse < T , U > ( orElseFn , mapFn ? , maybe ? ) { function fullOp ( fn , m ) { return m . isJust ? fn ( m . value ) : orElseFn ( ) ; } function partialOp ( fn ) ; function partialOp ( fn , curriedMaybe ) ; function partialOp ( fn , curriedMaybe ? ) { return curriedMaybe !== undefined ? fullOp ( fn , curriedMaybe ) : ( extraCurriedMaybe ) => fullOp ( fn , extraCurriedMaybe ) ; } if ( mapFn === undefined ) { return partialOp ; } else if ( maybe === undefined ) { return partialOp ( mapFn ) ; } else { return partialOp ( mapFn , maybe ) ; } } typeparam typeparam param andMaybe param maybe return export function and < T , U > ( andMaybe , maybe ) ; export function and < T , U > ( andMaybe ) ; export function and < T , U > ( andMaybe , maybe ? ) { const op = ( m ) => ( m . isJust ? andMaybe : nothing < U > ( ) ) ; return curry1 ( op , maybe ) ; } typeparam typeparam param thenFn param maybe returns export function andThen < T , U > ( thenFn , maybe ) ; export function andThen < T , U > ( thenFn ) ; export function andThen < T , U > ( thenFn , maybe ? ) { const op = ( m ) => ( m . isJust ? thenFn ( m . value ) : nothing < U > ( ) ) ; return maybe !== undefined ? op ( maybe ) : op ; } typeparam param defaultMaybe param maybe returns export function or < T > ( defaultMaybe , maybe ) ; export function or < T > ( defaultMaybe ) ; export function or < T > ( defaultMaybe , maybe ? ) { const op = ( m ) => ( m . isJust ? m : defaultMaybe ) ; return maybe !== undefined ? op ( maybe ) : op ; } typeparam param elseFn param maybe returns export function orElse < T > ( elseFn , maybe ) ; export function orElse < T > ( elseFn ) ; export function orElse < T > ( elseFn , maybe ? ) { const op = ( m ) => ( m . isJust ? m : elseFn ( ) ) ; return curry1 ( op , maybe ) ; } typeparam param defaultValue param maybe returns export function unwrapOr < T , U > ( defaultValue , maybe ) ; export function unwrapOr < T , U > ( defaultValue ) ; export function unwrapOr < T , U > ( defaultValue , maybe ? ) { const op = ( m ) => ( m . isJust ? m . value : defaultValue ) ; return curry1 ( op , maybe ) ; } typeparam param orElseFn param maybe returns export function unwrapOrElse < T , U > ( orElseFn , maybe ) ; export function unwrapOrElse < T , U > ( orElseFn ) ; export function unwrapOrElse < T , U > ( orElseFn , maybe ? ) { const op = ( m ) => ( m . isJust ? m . value : orElseFn ( ) ) ; return curry1 ( op , maybe ) ; } deprecated export function fromResult < T > ( result ) { return Toolbelt . fromResult ( result ) ; } typeparam param maybe returns export function toString < T extends { toString ( ) : string ; } > ( maybe ) { const body = maybe . isJust ? `(${ maybe . value . toString ( ) })` : '' ; return `${ maybe . variant }${ body }` ; } param maybe returns export function toJSON < T > ( maybe ) { return maybe . isJust ? { variant : maybe . variant , value : isInstance ( maybe . value ) ? maybe . value . toJSON ( ) : maybe . value , } : { variant : maybe . variant } ; } /**
  A lightweight object defining how to handle each variant of a {@linkcode Maybe}.
 */ export type Matcher < T , A > = { Just : ( value : T ) => A ; Nothing : ( ) => A ; } ; param matcher param maybe export function match < T , A > ( matcher , maybe ) ; export function match < T , A > ( matcher ) ; export function match < T , A > ( matcher , maybe ? ) { const op = ( curriedMaybe ) => mapOrElse ( matcher . Nothing , matcher . Just , curriedMaybe ) ; return curry1 ( op , maybe ) ; } param mb param ma export function equals < T > ( mb , ma ) ; export function equals < T > ( mb ) ; export function equals < T > ( mb , ma ? ) { const op = ( maybeA ) => maybeA . match ( { Just : ( aVal ) => mb . isJust && mb . value === aVal , Nothing : ( ) => mb . isNothing , } ) ; return curry1 ( op , ma ) ; } param maybeFn param maybe export function ap < T , U > ( maybeFn , maybe ) ; export function ap < T , U > ( maybeFn ) ; export function ap < T , U > ( maybeFn , maybe ? ) { const op = ( m ) => m . andThen ( ( val ) => maybeFn . map ( ( fn ) => fn ( val ) ) ) ; return curry1 ( op , maybe ) ; } param item export function isInstance < T > ( item ) { return item instanceof Maybe ; } export type Predicate < T > = ( element : T , index : number , array : T [ ] ) => boolean ; param predicate param array export function find < T > ( predicate , array ) ; export function find < T > ( predicate ) ; export function find < T > ( predicate , array ? ) { const op = ( a ) => Maybe . of ( a . find ( predicate ) ) ; return curry1 ( op , array ) ; } param array export function first < T > ( array ) { return Maybe . of ( array [ 0 ] ) ; } deprecated export const head = first ; param array export function last < T > ( array ) { return Maybe . of ( array [ array . length - 1 ] ) ; } param maybes export function transposeArray < T extends Array < Maybe < unknown > > > ( maybes ) { return maybes . reduce ( ( acc , m ) => acc . andThen ( ( ms ) => m . map ( ( m ) => [ ... ms , m ] ) ) , just ( [ ] as unknown [ ] ) as TransposedArray < T > ) as TransposedArray < T > ; } export type Unwrapped < T > = T extends Maybe < infer U > ? U : T ; export type TransposedArray < T extends Array < Maybe < unknown > > > = Maybe < { [ K in keyof T ] : Unwrapped < T [ K ] > ; } > ; deprecated export const all = transposeArray ; deprecated export const tuple = transposeArray ; deprecated export function transposeResult < T , E > ( result ) { return Toolbelt . transposeResult ( result ) ; } deprecated export function toOkOrErr < T , E > ( error , maybe ) ; export function toOkOrErr < T , E > ( error ) ; export function toOkOrErr < T , E > ( error , maybe ? ) { const op = ( m ) => ( m . isJust ? Result . ok < T , E > ( m . value ) : Result . err < T , E > ( error ) ) ; return maybe !== undefined ? op ( maybe ) : op ; } deprecated export function toOkOrElseErr < T , E > ( elseFn , maybe ) ; export function toOkOrElseErr < T , E > ( elseFn ) ; export function toOkOrElseErr < T , E > ( elseFn , maybe ? ) { const op = ( m ) => ( m . isJust ? Result . ok < T , E > ( m . value ) : Result . err < T , E > ( elseFn ( ) ) ) ; return curry1 ( op , maybe ) ; } param key param obj export function property < T , K extends keyof T > ( key , obj ) ; export function property < T , K extends keyof T > ( key ) ; export function property < T , K extends keyof T > ( key , obj ? ) { const op = ( a ) => Maybe . of ( a [ key ] ) as Maybe < NonNullable < T [ K ] > > ; return curry1 ( op , obj ) ; } param key param obj export function get < T , K extends keyof T > ( key , maybeObj ) ; export function get < T , K extends keyof T > ( key ) ; export function get < T , K extends keyof T > ( key , maybeObj ? ) { return curry1 ( andThen ( property < T , K > ( key ) ) , maybeObj ) ; } param fn export function wrapReturn < F extends AnyFunction , P extends Parameters < F > , R extends NonNullable < ReturnType < F > > > ( fn ) { return ( ... args ) => Maybe . of ( fn ( ... args ) ) as Maybe < R > ; } /**
  This is the standard *correct* definition for a function which is a proper
  subtype of all other functions: parameters of a function subtype must be
  *wider* than those of the base type, and return types must be *narrower*.
  Everything is wider than `never[]` and narrower than `unknown`, so any
  function is assignable to places this is used.
 */ export type AnyFunction = ( ... args : never [ ] ) => unknown ; /**
  The public interface for the {@linkcode Maybe} class *as a value*: a
  constructor and the associated static properties.
 */ export interface MaybeConstructor { new < T > ( value ? ) : Maybe < T > ; of : typeof MaybeImpl . of ; just : typeof MaybeImpl . just ; nothing : typeof MaybeImpl . nothing ; } /** A value which may ({@linkcode Just `Just<T>`}) or may not
 * ({@linkcode Nothing}) be present. */ export type Maybe < T > = Just < T > | Nothing < T > ; export const Maybe = MaybeImpl as MaybeConstructor ; export default Maybe ;