/* Copyright 2022 R3BL LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ import { TextColor } from "../tui-colors/style-builder" import { Optional } from "./core" import { anyToString } from "./data-class" import { SimpleReceiverFn, TruthyReceiverFn } from "./expression-lang-utils" // Option is based on Rust's Option enum and it is intended to be used in place of null and // undefined. Expressing !undefined && !null in TS: https://stackoverflow.com/a/63046469/2085356 export abstract class Option { readonly _isSome: boolean constructor(value: T | undefined | null) { if (value === undefined || value === null) { this._isSome = false } else { this._isSome = true } } // https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates isSome(): this is Some { return this._isSome } // https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates isNone(): this is None { return !this._isSome } abstract toString(): string static none = (): None => Object.freeze(new None()) static some = (arg: T): Some => Object.freeze(new Some(arg)) static create = (arg: Optional): Option => arg === undefined || arg === null ? Option.none() : Option.some(arg) } export class None extends Option { constructor() { super(undefined) } public toString(): string { return `None` } } export class Some extends Option { readonly _value: T constructor(value: T) { super(value) this._value = value } public toString(): string { return `Some(${anyToString(this.value)})` } public get value(): T { return this._value } } // Expressions that work w/ `Option`. export const _callIfSome = (context: Option, receiver: TruthyReceiverFn): void => { if (context instanceof Some) receiver(context.value) } export const _callIfNone = (context: Option, receiver: SimpleReceiverFn): void => { if (context instanceof None) receiver() } // Similar to `debug!` macro in Rust. export const DebugStyle = Object.freeze({ msgStyle: TextColor.builder.cyan.build(), argStyle: TextColor.builder.green.build(), }) export function debug(msg: string, obj: any) { console.log(DebugStyle.msgStyle(msg), DebugStyle.argStyle(anyToString(obj))) return obj }