Full Code of OliverBrotchie/optionals for AI

main f243aa35699e cached
12 files
37.6 KB
10.4k tokens
50 symbols
1 requests
Download .txt
Repository: OliverBrotchie/optionals
Branch: main
Commit: f243aa35699e
Files: 12
Total size: 37.6 KB

Directory structure:
gitextract_b_g0ihly/

├── .gitignore
├── .vscode/
│   └── settings.json
├── LICENSE
├── README.md
├── deno.json
├── mod.ts
├── scripts/
│   ├── build_npm.json
│   └── build_npm.ts
└── src/
    ├── option.ts
    ├── result.ts
    └── tests/
        ├── option.test.ts
        └── result.test.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================

.DS_Store
coverage
npm


================================================
FILE: .vscode/settings.json
================================================
{
    "deno.enable": true,
    "deno.lint": true,
    "deno.unstable": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode"
}

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2021 Oliver Brotchie

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<div align="center">

  <h1><code>Optionals</code></h1>

<strong>Rust-like error handling and options for TypeScript, Node and Deno!</strong>

</div>

This module allows you to remove `null` and `undefined` from your projects with the help of ES6 Symbols and helper methods. Inspired by Rust's `Option`, `Result` enums.

## Why should you use Optionals?

The standard practice of returning `null` or `undefined` when no other value can be returned means that there is no simple way to express the difference between a function that has returned "nothing" and a `null` return type. There are also no easy ways to handle errors in a functional pattern. Rust's implementation of `Option` and `Result` guarantees correctness by expressly forcing correct result-handling practices.

This module provides a minimal, fast and simple way to create expressive functions and perform better pattern matching on resulting values! 🚀

## Usage

```ts
// Result
import { Result, Ok, Err } from "https://deno.land/x/optionals@v2.0.2/mod.ts";

// Option
import {
  Option,
  Some,
  None,
} from "https://deno.land/x/optionals@v2.0.2/mod.ts";
```

## Documentation

Please find further documentation on the [doc](https://doc.deno.land/https://deno.land/x/optionals@v2.0.2/mod.ts) page!


================================================
FILE: deno.json
================================================
{
  "tasks": {
    "test": "deno test --coverage=coverage",
    "lcov": "deno coverage coverage --lcov --output=coverage/report.lcov",
    "cover": "deno task clean && deno task test && deno task lcov && genhtml -o coverage/html coverage/report.lcov",
    "build": "deno run -A scripts/build_npm.ts --cp=LICENSE,README.md",
    "publish": "cd ./npm && npm publish",
    "clean": "rm -rf ./npm ./coverage"
  }
}


================================================
FILE: mod.ts
================================================
/**
 * # `Optionals`
 *
 * **Rust-like error handling and options for TypeScript and Deno!**
 *
 * This module provides two classes `Result` and `Option`:
 *  - `Option` provides a lovely way to express functions that may return nothing.
 *  - `Result` lets you tackle errors using with an easy to use functional pattern.
 *
 */

import { Result, Ok, Err } from "./src/result.ts";
import { Option, Some, None, none } from "./src/option.ts";

export { Result, Ok, Err, Option, Some, None, none };


================================================
FILE: scripts/build_npm.json
================================================
{
  "$schema": "https://json.schemastore.org/package.json",
  "name": "rust-optionals",
  "version": "3.0.0",
  "description": "Rust-like error handling and options for TypeScript, Node, and Deno!",
  "keywords": [
    "rust",
    "error-handling",
    "option",
    "result",
    "optionals"
  ],
  "homepage": "https://github.com/OliverBrotchie/optionals#readme",
  "bugs": "https://github.com/OliverBrotchie/optionals/issues",
  "license": "MIT",
  "contributors": [
    "Oliver Brotchie <oliver@unazoomer.net>"
  ],
  "repository": {
    "type": "git",
    "url": "https://github.com/OliverBrotchie/optionals.git"
  }
}

================================================
FILE: scripts/build_npm.ts
================================================
/*
 * Contributed 2022 by Aaron Huggins under the MIT license.
 */
import { parse } from "https://deno.land/std@0.160.0/flags/mod.ts";
import { basename } from "https://deno.land/std@0.160.0/path/mod.ts";
import {
  inc as increment,
  ReleaseType,
} from "https://deno.land/std@0.160.0/semver/mod.ts";
import {
  build,
  BuildOptions,
  emptyDir,
} from "https://deno.land/x/dnt@0.31.0/mod.ts";

await emptyDir("./npm");

function versionHandler(current: string, releaseType: ReleaseType): string {
  const releaseTypes: ReleaseType[] = [
    "major",
    "minor",
    "patch",
    "pre",
    "premajor",
    "preminor",
    "prepatch",
    "prerelease",
  ];

  if (releaseTypes.includes(releaseType)) {
    return increment(current, releaseType) ?? current;
  }

  return current;
}

const scriptName = basename(import.meta.url, ".ts");
const logTag = `[${scriptName}]`;
const packageFile = `./scripts/${scriptName}.json`;
const packageText = await Deno.readTextFile(packageFile);
const packageJSON = <BuildOptions["package"]>JSON.parse(packageText);
const { version } = packageJSON;
const args = parse(Deno.args, {
  string: ["cp", "release"],
  default: {
    cp: "",
    release: "",
  },
});
const release = <ReleaseType>args.release;
packageJSON.version = versionHandler(version, release);

await build({
  entryPoints: ["./mod.ts"],
  outDir: "./npm",
  shims: {
    deno: true,
  },
  package: {
    ...packageJSON,
  },
});

// post build steps
for (const filepath of args.cp.split(/,/g)) {
  await Deno.copyFile(filepath, `npm/${filepath}`);
}

if (packageJSON.version === version) {
  console.log(
    `${logTag} Version did not change; nothing to deploy. ${packageJSON.name} v${version}`
  );
} else {
  await Deno.writeTextFile(packageFile, JSON.stringify(packageJSON, null, 2));
  console.log(
    `${logTag} ${packageJSON.name} v${packageJSON.version} ready to deploy!`
  );
}


================================================
FILE: src/option.ts
================================================
import { Err, Ok, Result } from "./result.ts";

/**
 * The primitive None value.
 *
 * _Note: To construct a None variant Option, please use `None()` instead._
 */
export const none = Symbol("None");

/**
 * A Rust-like Option class.
 *
 * _Note: Please use either `Some` or `None` to construct an Option._
 *
 * @example
 * ```
 * function divide(left: number, right: number): Option<number> {
 *   if (right === 0) return None();
 *
 *   return Some(left / right);
 * }
 *
 * ```
 */
export class Option<T> {
  private val: T | typeof none;

  /**
   * A constructor for an Option.
   *
   * _Note: Please use either `Some` or `None` to construct Options._
   *
   * @param {T | typeof none} input The value to wrap in an Option.
   */
  constructor(input: T | typeof none) {
    this.val = input;
  }

  /**
   * Converts Option into a String for display purposes.
   */
  get [Symbol.toStringTag]() {
    return `Option`;
  }

  /**
   * Iterator support for Option.
   *
   * _Note: This method will only yeild if the Option is Some._
   * @returns {IterableIterator<T>}
   */
  *[Symbol.iterator]() {
    if (this.isSome()) yield this.val;
  }

  /**
   * Returns true if contained value isnt None.
   * @returns {boolean}
   */
  isSome(): boolean {
    return this.val !== none;
  }

  /**
   * Returns true if contained value is None.
   *
   * @returns {boolean}
   */
  isNone(): boolean {
    return this.val === none;
  }

  /**
   * Returns the contained Some value, consuming the Option.
   * Throws an Error with a given message if the contained value is None.
   *
   * @param {string} msg An error message to throw if contained value is None.
   * @returns {T}
   */
  expect(msg: string): T {
    if (this.isNone()) {
      throw new Error(msg);
    }

    return this.val as T;
  }

  /**
   * Returns the contained Some value, consuming the Option.
   * Throws an Error if contained value is None.
   *
   * @returns {T}
   */
  unwrap(): T {
    if (this.isNone()) {
      throw new Error(`Unwrap called on None`);
    }

    return this.val as T;
  }

  /**
   * Returns the contained Some value or a provided default.
   *
   * @param {T} fallback A default value to return if contained value is an Option.
   * @returns {T}
   */
  unwrapOr(fallback: T): T {
    if (this.isNone()) {
      return fallback;
    }

    return this.val as T;
  }

  /**
   * Returns the contained Some value or computes it from a closure.
   *
   * @param {Function} fn A function that computes a new value.
   * @returns {T}
   */
  unwrapOrElse(fn: () => T): T {
    if (this.isNone()) {
      return fn();
    }

    return this.val as T;
  }

  /**
   * Maps an Option<T> to Option<U> by applying a function to a contained Some value, leaving None values untouched.
   *
   * @param {Function} fn A mapping function.
   * @returns {Option<U>}
   */
  map<U>(fn: (input: T) => U): Option<U> {
    if (this.isSome()) {
      return new Option<U>(fn(this.val as T));
    }
    return this as unknown as Option<U>;
  }

  /**
   * Returns the provided fallback (if None), or applies a function to the contained value.
   *
   * @param {U} fallback A defualt value
   * @param {Function} fn A mapping function.
   * @returns {U}
   */
  mapOr<U>(fallback: U, fn: (input: T) => U): U {
    if (this.isSome()) {
      return fn(this.val as T);
    }

    return fallback;
  }

  /**
   * Returns `or` if the Option is None, otherwise returns self.
   *
   * @param {Option<T>} or An alternative Option value
   * @returns {Option<T>}
   */
  or(or: Option<T>): Option<T> {
    if (this.isSome()) {
      return this;
    }

    return or;
  }

  /**
   * Transforms the `Option<T>` into a `Result<T, E>`, mapping Some to Ok and None to Err.
   *
   * @param {E} err An error to return if the Option is None.
   * @returns {Result<T, E>}
   *
   * @example
   * ```
   * const result = Some(2).okOr("Error"); // => Ok(2)
   * ```
   */
  okOr<E extends Error>(err: E | string): Result<T, E> {
    if (this.isSome()) {
      return Ok(this.val as T);
    } else {
      return Err(err);
    }
  }

  /**
   * Returns contained value for use in matching.
   *
   * _Note: Please only use this to match against in `if` or `swtich` statments._
   *
   * @returns {T | typeof none}
   * @example
   * ```ts
   * function coolOrNice(input: Option<string>): Option<void> {
   *   switch (input.peek()) {
   *     case "cool":
   *       console.log("Input was the coolest!");
   *       break;
   *     case "nice":
   *       console.log("Input was was the nicest!");
   *       break
   *     default:
   *       return None();
   *   }
   *   return Some()
   * }
   * ```
   */
  peek(): T | typeof none {
    return this.val;
  }

  /**
   * Converts from Option<Option<T> to Option<T>
   * @returns Option<T>
   */
  flatten(): Option<T> {
    if (this.val instanceof Option) {
      return this.val
    }
    return this
  }

  /**
   * Run a closure and convert it into an Option.
   * If the function returns `null` or `undefined`, an Option containing None will be reutrned.
   *
   * _Note: Please use `fromAsync` to capture the result of asynchronous closures._
   * @param {Function} fn The closure to run.
   * @returns {Option<T>} The result of the closure.
   */
  static from<T>(fn: () => T | null | undefined): Option<T> {
    const result = fn();
    if (result === null || result === undefined) {
      return new Option<T>(none);
    } else {
      return new Option<T>(result);
    }
  }

  /**
   * Run an asynchronous closure and convert it into an Option.
   * If the function returns `null` or `undefined`, an Option containing None will be reutrned.
   *
   * _Note: Please use `from` to capture the result of synchronous closures._
   * @param {Function} fn The closure to run.
   * @returns {Promise<Option<T>>} The result of the closure.
   */
  static async fromAsync<T>(
    fn: () => Promise<T | null | undefined>
  ): Promise<Option<T>> {
    const result = await fn();
    if (result === null || result === undefined) {
      return new Option<T>(none);
    } else {
      return new Option<T>(result);
    }
  }
}

/**
 * Construct an Option from a value other than None.
 *
 * @param {Exclude<T, typeof none>} input a value that isnt None.
 * @returns {Option<T>}
 * @example
 * ```ts
 * function divide(left: number, right: number): Option<number> {
 *   if (right === 0) return None();
 *
 *   return Some(left / right);
 * }
 *
 * ```
 *
 * @example
 * ```ts
 * const foo = Some("Value");
 *
 * if (foo instanceof Some) {
 *  // Do something
 * }
 * ```
 */
export function Some<T>(input: T): Option<T> {
  return new Option<T>(input as T);
}

Object.defineProperty(Some, Symbol.hasInstance, {
  value: <T>(instance: Option<T>): boolean => {
    if (typeof instance !== "object") return false;
    return instance?.isSome() || false;
  },
});

/**
 * Construct the None variant of Option.
 *
 * @returns {Option<T>}
 * @example
 * ```ts
 *  function divide(left: number, right: number): Option<number> {
 *   if (right === 0) return None();
 *
 *   return Some(left / right);
 * }
 * ```
 * @example
 * ```ts
 * const foo = None();
 *
 * if (foo instanceof None) {
 *  // Do something
 * }
 * ```
 */
export function None<T>(): Option<T> {
  return new Option<T>(none);
}

Object.defineProperty(None, Symbol.hasInstance, {
  value: <T>(instance: Option<T>): boolean => {
    if (typeof instance !== "object") return false;
    return instance?.isNone() || false;
  },
});


================================================
FILE: src/result.ts
================================================
// deno-lint-ignore-file no-prototype-builtins
/* eslint-disable no-prototype-builtins */

import { None, Option, Some } from "./option.ts";

/**
 * A Rust-like Result class.
 *
 * _Note: Please use either Ok or Err to construct Results._
 *
 * @example
 * ```ts
 * function divide(left: number, right: number): Result<number, Error> {
 *   if (right === 0) return Err("Divided by zero");
 *
 *   return Ok(left / right);
 * }
 *
 * ```
 */
export class Result<T, E extends Error> {
  private val: T | E;

  /**
   * A constructor for a Result.
   *
   * @param {T | E} input The Result value.
   *
   * _Note: Please use either `Ok` or `Err` to construct Results._
   */
  constructor(input: T | E) {
    this.val = input;
  }

  /**
   * Converts Result into a String for display purposes.
   */
  get [Symbol.toStringTag]() {
    return `Result`;
  }

  /**
   * Iterator support for Result.
   *
   * _Note: This method will only yeild if the Result is Ok._
   * @returns {IterableIterator<T>}
   */
  *[Symbol.iterator]() {
    if (this.isOk()) yield this.val;
  }

  /**
   * Returns true if contained value isnt an error.
   *
   * @returns {boolean}
   */
  isOk(): boolean {
    return !(
      this.val instanceof Error ||
      (this.val &&
        typeof this.val === "object" &&
        Error.isPrototypeOf(this.val))
    );
  }

  /**
   * Returns true if contained value is an error.
   *
   * @returns {boolean}
   */
  isErr(): boolean {
    return (
      this.val instanceof Error ||
      (this.val &&
        typeof this.val === "object" &&
        Error.isPrototypeOf(this.val))
    );
  }

  private formatError(err: Error) {
    err.stack = `${err.message}: ${
      (this.val as E).stack
        ? "\n\t" + ((this.val as E).stack as string).split("\n").join("\n\t")
        : (this.val as E).message
    }`;

    throw err;
  }

  /**
   * Returns the contained Ok value, consuming the Result.
   * Throws an Error with a given message if contained value is not Ok.
   *
   * @param {string} msg An error message to throw if contained value is an Error.
   * @returns {T}
   */
  expect(msg: string): T {
    if (this.isErr()) {
      this.formatError(new Error(msg));
    }

    return this.val as T;
  }

  /**
   * Returns the contained Err value, consuming the Result.
   * Throws an Error with a given message if contained value is not an Err.
   *
   * @param {string} msg An error message to throw if contained value is Ok.
   * @returns {T}
   */
  expectErr(msg: string): T {
    if (this.isOk()) {
      this.formatError(new Error(msg));
    }

    return this.val as T;
  }

  /**
   * Returns the contained Ok value, consuming the Result.
   * Throws an Error if contained value is not Ok.
   *
   * @returns {T}
   */
  unwrap(): T {
    if (this.isErr()) {
      this.formatError(new Error(`Unwrap called on ${(this.val as E).name}`));
    }

    return this.val as T;
  }

  /**
   * Returns the contained Error value, consuming the Result.
   * Throws an Error if contained value is not an Error.
   *
   * @returns {E}
   */
  unwrapErr(): E {
    if (this.isOk()) {
      throw new Error(
        `UnwrapError called on value - ${this.val as unknown as string}`
      );
    }

    return this.val as E;
  }

  /**
   * Returns the contained Ok value or a provided default.
   *
   * @param {T} fallback A default value to return if contained value is an Error.
   * @returns {T}
   */
  unwrapOr(fallback: T): T {
    if (this.isErr()) {
      return fallback;
    }

    return this.val as T;
  }

  /**
   * Returns the contained Ok value or computes it from a closure.
   *
   * @param {Function} fn A function that computes a new value.
   * @returns {T}
   */
  unwrapOrElse(fn: (input: E) => T): T {
    if (this.isErr()) {
      return fn(this.val as E);
    }

    return this.val as T;
  }

  /**
   * Maps a Result<T, E> to Result<U, E> by applying a function to a contained Ok value, leaving an Error value untouched.
   *
   * @param {Function} fn A mapping function.
   * @returns {Result<U, E>}
   */
  map<U>(fn: (input: T) => U): Result<U, E> {
    if (this.isOk()) {
      return new Result<U, E>(fn(this.val as T));
    }

    return this as unknown as Result<U, E>;
  }

  /**
   * Maps a Result<T, E> to Result<T, U> by applying a function to a contained Error value, leaving an Ok value untouched.
   *
   * @param {Function} fn A mapping function.
   * @returns {Result<T, U>}
   */
  mapErr<U extends Error>(fn: (input: E) => U): Result<T, U> {
    if (this.isOk()) {
      return this as unknown as Result<T, U>;
    }

    return new Result<T, U>(fn(this.val as E));
  }

  /**
   * Returns the provided fallback (if Error), or applies a function to the contained value.
   *
   * @param {U} fallback A defualt value
   * @param {Function} fn A mapping function.
   * @returns {U}
   */
  mapOr<U>(fallback: U, fn: (input: T) => U): U {
    if (this.isOk()) {
      return fn(this.val as T);
    }

    return fallback;
  }

  /**
   * Returns `or` if the result is Error, otherwise returns self.
   *
   * @param {Result<T, E>} or An alternative Result value
   * @returns {Result<T, E>}
   */
  or(or: Result<T, E>): Result<T, E> {
    if (this.isOk()) {
      return this;
    }

    return or;
  }

  /**
   * Converts from `Result<T, E>` to `Option<T>`.
   *
   * @returns {Option<T>}
   *
   * @example
   * ```ts
   * const option = Err("Some Error").ok(); // => None()
   * ```
   */
  ok(): Option<T> {
    if (this.isOk()) {
      return Some(this.val as T);
    }

    return None();
  }

  /**
   * Returns contained value for use in matching.
   *
   * _Note: Please only use this to match against in `if` or `swtich` statments._
   *
   * @returns {T | E}
   * @example
   * ```ts
   * function coolOrNice(input: Result<string, Error>): Result<void, Error> {
   *   switch (input.peek()) {
   *     case "cool":
   *       console.log("Input was the coolest!");
   *       break;
   *     case "nice":
   *       console.log("Input was was the nicest!");
   *       break
   *     default:
   *       return Err("Input neither cool nor nice.");
   *   }
   *   return Ok()
   * }
   * ```
   */
  peek(): T | E {
    return this.val;
  }

  /**
   * Throws contained Errors, consuming the Result.
   */
  throw(): void {
    if (this.isErr()) {
      throw this.val;
    }
  }

  /**
   * Converts from Result<Result<T, E>, E> to Result<T, E>
   * @returns Option<T>
   */
  flatten(): Result<T, E> {
    if (this.val instanceof Result) {
      return this.val
    }
    return this
  }

  /**
   * Run a closure in a `try`/`catch` and convert it into a Result.
   *
   * _Note: Please use `fromAsync` to capture the Result of asynchronous closures._
   * @param {Function} fn The closure to run
   * @returns {Result<T, Error>} The Result of the closure
   */
  static from<T>(fn: () => T): Result<T, Error> {
    try {
      return new Result<T, Error>(fn());
    } catch (e: unknown) {
      return new Result<T, Error>(e as Error);
    }
  }

  /**
   * Run an asynchronous closure in a `try`/`catch` and convert it into a Result.
   *
   * _Note: Please use `from` to capture the Result of synchronous closures._
   * @param {Function} fn The synchronous closure to run
   * @returns {Promise<Result<T, Error>>} The Result of the closure
   */
  static async fromAsync<T>(fn: () => Promise<T>): Promise<Result<T, Error>> {
    try {
      return new Result<T, Error>(await fn());
    } catch (e: unknown) {
      return new Result<T, Error>(e as Error);
    }
  }

  /**
   * Partition an array of Results into Ok values and Errors
   *
   * @param {Array<Result<T, E>>} input An array of Results
   * @returns {{ok: Array<T>, err: Array<E>}}
   *
   * @example
   * ```ts
   * const results = [Ok(2), Ok(16), Err("Something went wrong!")]
   *
   * Result.partition(results) // { ok:[2, 16], err:[Error("Something went wrong!")]}
   *
   * ```
   */
  static partition<T, E extends Error>(
    input: Array<Result<T, E>>
  ): { ok: Array<T>; err: Array<E> } {
    return input.reduce(
      (acc: { ok: Array<T>; err: Array<E> }, e) => {
        if (e.isOk()) acc.ok.push(e.unwrap());
        else acc.err.push(e.unwrapErr());

        return acc;
      },
      {
        ok: [],
        err: [],
      }
    );
  }
}

/**
 * Return a non-error value result.
 *
 * @param {Exclude<T, E>} input a value that does not extend the `Error` type.
 * @returns {Result<T, E>}
 * @example
 * ```ts
 * function divide(left: number, right: number): Result<number, Error> {
 *   if (right === 0) return Err("Divided by zero");
 *
 *   return Ok(left / right);
 * }
 *
 * ```
 *
 * @example
 * ```ts
 * const foo = Ok("Foo!");
 *
 * if (foo instanceof Ok) {
 *  // Do something
 * }
 * ```
 */
export function Ok<T, E extends Error>(input?: T) {
  return new Result<T, E>(input as T);
}

Object.defineProperty(Ok, Symbol.hasInstance, {
  value: <T, E extends Error>(instance: Result<T, E>): boolean => {
    if (typeof instance !== "object") return false;
    return instance?.isOk() || false;
  },
});

/**
 * Return a error result.
 *
 * @param {E | string} input a value that extends the `Error` type.
 * @returns {Result<T, E>}
 * @example
 * ```ts
 * function divide(left: number, right: number): Result<number, Error> {
 *   if (right === 0) return Err("Divided by zero");
 *
 *   return Ok(left / right);
 * }
 *
 * ```
 *
 * @example
 * ```ts
 * const foo = Err(new Error("Foo!"));
 *
 * if (foo instanceof Err) {
 *  // Do something
 * }
 * ```
 */
export function Err<T, E extends Error>(input: E | string): Result<T, E> {
  if (typeof input === "string") {
    return new Result<T, Error>(new Error(input)) as Result<T, E>;
  }
  return new Result<T, E>(input);
}

Object.defineProperty(Err, Symbol.hasInstance, {
  value: <T, E extends Error>(instance: Result<T, E>): boolean => {
    if (typeof instance !== "object") return false;
    return instance?.isErr() || false;
  },
});


================================================
FILE: src/tests/option.test.ts
================================================
import { Option, Some, None, none } from "../option.ts";
import {
  assertEquals,
  assert,
  fail,
} from "https://deno.land/std@0.159.0/testing/asserts.ts";

const symbol = Symbol("Fake None");

Deno.test("Option", async (t) => {
  await t.step("isSome - Should correctly identify a Some value.", () => {
    assert(new Option("Some").isSome());
    assert(!new Option(none).isSome());
    assert(new Option(symbol).isSome());
  });

  await t.step("isNone - Should correctly identify a None value.", () => {
    assert(!new Option("Some").isNone());
    assert(new Option(none).isNone());
    assert(!new Option(symbol).isNone());
  });

  await t.step("Symbol.toStringTag - Should return correct value.", () => {
    assertEquals(new Option("Some")[Symbol.toStringTag], "Option");
  });

  await t.step(
    "Symbol.iterator - Should return an array with one element.",
    () => {
      assertEquals([...new Option("Ok")], ["Ok"]);
    }
  );

  await t.step("Symbol.iterator None - Should return an empty array.", () => {
    assertEquals([...new Option(none)], []);
  });

  await t.step("expect - Should get contained value.", () => {
    const res = new Option("Some").expect("Test");
    assertEquals(res, "Some");
  });

  await t.step(
    "expect None - Should throw an error with a message if Option contains None.",
    () => {
      try {
        new Option(none).expect("Alternative");
      } catch (e) {
        assertEquals(e, new Error("Alternative"));
        return;
      }
      fail("Method did not throw.");
    }
  );

  await t.step("unwrap - Should get contained value.", () => {
    const res = new Option("Some").unwrap();
    assertEquals(res, "Some");
  });

  await t.step(
    "unwrap None - Should throw an error if Option contains None.",
    () => {
      try {
        new Option(none).unwrap();
      } catch (_) {
        return;
      }
      fail("Method did not throw.");
    }
  );

  await t.step("unwrapOr - Should get contained value.", () => {
    const res = new Option("Some").unwrapOr("Test");
    assertEquals(res, "Some");
  });

  await t.step("unwrapOr None - Should get default value.", () => {
    const res = new Option<string>(none).unwrapOr("Ok");
    assertEquals(res, "Ok");
  });

  await t.step("unwrapOrElse - Should get contained value.", () => {
    const res = new Option("Ok").unwrapOrElse(() => "Test");
    assertEquals(res, "Ok");
  });

  await t.step("unwrapOrElse None - Should get computed value.", () => {
    const res = new Option<string>(none).unwrapOrElse(() => "Ok");
    assertEquals(res, "Ok");
  });

  await t.step("map - Should get mapped value.", () => {
    const res = new Option(123).map(() => "Test");
    assertEquals(res.peek(), "Test");
  });

  await t.step("map None - Should leave value untouched.", () => {
    const res = new Option<string>(none).map(() => "Test");
    assert(res.isNone());
  });

  await t.step("mapOr - Should get mapped value.", () => {
    const res = new Option(123).mapOr("Test", () => "Ok");
    assertEquals(res, "Ok");
  });

  await t.step("mapOr None - Should get Error.", () => {
    const res = new Option<string>(none).mapOr("Ok", () => "Test");
    assertEquals(res, "Ok");
  });

  await t.step("peek - Should get contained value.", () => {
    const res = new Option("Ok").peek();
    assertEquals(res, "Ok");
  });

  await t.step("or - Should get contained value.", () => {
    const res = new Option("Ok").or(new Option("Test"));
    assertEquals(res.peek(), "Ok");
  });

  await t.step("or None - Should get default value.", () => {
    const res = new Option<string>(none).or(new Option("Ok"));
    assertEquals(res.peek(), "Ok");
  });

  await t.step("okOr - Should convert Some to Ok.", () => {
    const res = new Option("Ok").okOr("Test");
    assertEquals(res.unwrap(), "Ok");
    assertEquals(res.isOk(), true);
  });

  await t.step("okOr None - Should convert None to Err.", () => {
    const res = new Option<string>(none).okOr("Err");
    assertEquals(res.unwrapErr(), new Error("Err"));
    assertEquals(res.isErr(), true);
  });

  await t.step("flatten - Should converts from Option<Option<T>> to Option<T>", () => {
    const res = new Option<Option<string>>(new Option<string>('test'))
    assertEquals(res.flatten(), new Option('test'))
  })
});

Deno.test("Result - Supporting Function Tests", async (t) => {
  await t.step("Some - Should return Some result.", () => {
    const res = Some("Test");
    assertEquals(res.isSome(), true);
    assertEquals(res.peek(), "Test");
  });

  await t.step("Some instanceof - Should return true.", () => {
    const res = Some("Test");
    assert(res instanceof Some);
  });

  await t.step("None - Should return None result.", () => {
    const res = None();
    assertEquals(res.isNone(), true);
  });

  await t.step("None instanceof - Should return true.", () => {
    const res = None();
    assert(res instanceof None);
  });

  await t.step("from - Should return Ok result.", () => {
    const res = Option.from(() => "Test");
    assert(res.isSome());
    assertEquals(res.peek(), "Test");
  });

  await t.step("from Null - Should return None result.", () => {
    const res = Option.from(() => {
      return null;
    });
    assert(res.isNone());
  });

  await t.step("from Undefined - Should return None result.", () => {
    const res = Option.from(() => {
      return undefined;
    });
    assert(res.isNone());
  });

  await t.step("fromAsync - Should return Ok result.", async () => {
    const res = await Option.fromAsync(
      async () => await Promise.resolve("Test")
    );
    assert(res.isSome());
    assertEquals(res.peek(), "Test");
  });

  await t.step("fromAsync Null - Should return None result.", async () => {
    const res = await Option.fromAsync(async () => await Promise.resolve(null));
    assert(res.isNone());
  });

  await t.step("fromAsync Undefined - Should return None result.", async () => {
    const res = await Option.fromAsync(
      async () => await Promise.resolve(undefined)
    );
    assert(res.isNone());
  });
});


================================================
FILE: src/tests/result.test.ts
================================================
import { Result, Ok, Err } from "../result.ts";
import {
  assertEquals,
  assert,
  fail,
} from "https://deno.land/std@0.159.0/testing/asserts.ts";

class TestError extends Error {
  name = "TestError";
}

class ErrorLookAlike {
  name = "ErrorLookAlike";
  message: string;
  stack?: string;

  constructor(message: string) {
    this.message = message;
  }
}

Deno.test("Result", async (t) => {
  await t.step(
    "isOk - Should correctly identify an Ok value & any extended Error class.",
    () => {
      assert(new Result("Ok").isOk());
      assert(!new Result(new Error("Test")).isOk());
      assert(!new Result(new TestError("Test")).isOk());
      assert(new Result(new ErrorLookAlike("Test")).isOk());
    }
  );

  await t.step(
    "isErr - Should correctly identify an Error & any extended class.",
    () => {
      assert(!new Result("Ok").isErr());
      assert(new Result(new Error("Test")).isErr());
      assert(new Result(new TestError("Test")).isErr());
      assert(!new Result(new ErrorLookAlike("Test")).isErr());
    }
  );

  await t.step("Symbol.toStringTag - Should return correct value.", () => {
    assertEquals(new Result("Ok")[Symbol.toStringTag], "Result");
  });

  await t.step(
    "Symbol.iterator - Should return an array with one element.",
    () => {
      assertEquals([...new Result("Ok")], ["Ok"]);
    }
  );

  await t.step("Symbol.iterator Err - Should return an empty array.", () => {
    assertEquals([...new Result(new Error("Test"))], []);
  });

  await t.step("expect - Should get contained value.", () => {
    const res = new Result("Ok").expect("Test");
    assertEquals(res, "Ok");
  });

  await t.step(
    "expect Error - Should throw an Error with a message if Result contains Error.",
    () => {
      try {
        new Result(new Error("Test")).expect("Alternative");
      } catch (e) {
        assertEquals(e, new Error("Alternative"));
        return;
      }
      fail("Method did not throw.");
    }
  );

  await t.step("expectErr - Should get contained Error value.", () => {
    const res = new Result(new Error("Test")).expectErr("Alternative");
    assertEquals(res, new Error("Test"));
  });

  await t.step(
    "expectErr Ok - Should throw an Error with a message if Result contains Ok.",
    () => {
      try {
        new Result("Ok").expectErr("Test");
      } catch (e) {
        assertEquals(e, new Error("Test"));
        return;
      }
      fail("Method did not throw.");
    }
  );

  await t.step("unwrap - Should get contained value.", () => {
    const res = new Result("Ok").unwrap();
    assertEquals(res, "Ok");
  });

  await t.step("unwrap Error - Should throw an Error.", () => {
    const err = new Error("Test");
    try {
      new Result(err).unwrap();
    } catch (e) {
      assertEquals((e as Error).message, "Unwrap called on Error");
      assertEquals(typeof (e as Error).stack, "string");
    }
  });

  await t.step("unwrap Error (no stack) - Should throw an Error.", () => {
    const err = new Error("Test");
    delete err.stack;
    try {
      new Result(err).unwrap();
    } catch (e) {
      assertEquals((e as Error).message, "Unwrap called on Error");
      assertEquals((e as Error).stack, "Unwrap called on Error: Test");
    }
  });

  await t.step("unrwapErr - Should get contained Error value.", () => {
    const err = new Result(new Error("Test")).unwrapErr();
    assertEquals(err.message, "Test");
  });

  await t.step(
    "unwrapErr Ok - Should throw an Error if Result contains Ok.",
    () => {
      try {
        new Result("Ok").unwrapErr();
      } catch (_) {
        return;
      }
      fail("Method did not throw.");
    }
  );

  await t.step("unwrapOr - Should get contained value.", () => {
    const res = new Result("Ok").unwrapOr("Test");
    assertEquals(res, "Ok");
  });

  await t.step("unwrapOr Error - Should get default value.", () => {
    const res = new Result<string, Error>(new Error("Test")).unwrapOr("Ok");
    assertEquals(res, "Ok");
  });

  await t.step("unwrapOrElse - Should get contained value.", () => {
    const res = new Result("Ok").unwrapOrElse(() => "Test");
    assertEquals(res, "Ok");
  });

  await t.step("unwrapOrElse Error - Should get computed value.", () => {
    const res = new Result<string, Error>(new Error("Test")).unwrapOrElse(
      () => "Ok"
    );
    assertEquals(res, "Ok");
  });

  await t.step("map - Should get mapped value.", () => {
    const res = new Result(123).map(() => "Test");
    assertEquals(res.peek(), "Test");
  });

  await t.step("map Error - Should get Error.", () => {
    const res = new Result<string, Error>(new Error("Test")).map(() => "Test");
    assert(res.isErr());
  });

  await t.step("mapErr - Should get mapped value.", () => {
    const res = new Result<string, Error>(new Error("Test")).mapErr(
      () => new TestError("Ok")
    );
    assertEquals(res.unwrapErr().name, "TestError");
  });

  await t.step("mapErr Ok - Should return Ok.", () => {
    const res = new Result<string, Error>("Ok").mapErr(
      () => new TestError("Test")
    );
    assertEquals(res.unwrap(), "Ok");
  });

  await t.step("mapOr - Should get mapped value.", () => {
    const res = new Result(123).mapOr("Test", () => "Ok");
    assertEquals(res, "Ok");
  });

  await t.step("mapOr Error - Should get Error.", () => {
    const res = new Result<string, Error>(new Error("Test")).mapOr(
      "Ok",
      () => "Test"
    );
    assertEquals(res, "Ok");
  });

  await t.step("peek - Should get contained value.", () => {
    const res = new Result("Ok").peek();
    assertEquals(res, "Ok");
  });

  await t.step("or - Should get contained value.", () => {
    const res = new Result("Ok").or(new Result("Test"));
    assertEquals(res.peek(), "Ok");
  });

  await t.step("or Error - Should get default value.", () => {
    const res = new Result<string, Error>(new Error("Test")).or(
      new Result("Ok")
    );
    assertEquals(res.peek(), "Ok");
  });

  await t.step("throw - Should throw an Error.", () => {
    try {
      new Result(new Error("Test")).throw();
    } catch (_) {
      return;
    }
    fail("Method did not throw.");
  });

  await t.step("throw Ok - Should not throw an Error.", () => {
    new Result("Ok").throw();
  });

  await t.step("ok - Should convert Ok to Some.", () => {
    const res = new Result("Ok").ok();
    assertEquals(res.unwrap(), "Ok");
    assertEquals(res.isSome(), true);
  });

  await t.step("ok Error - Should convert Err to None.", () => {
    const res = new Result<string, Error>(new Error("Test")).ok();
    assert(res.isNone());
  });

  await t.step('flatten - Should converts from Result<Result<T, E>, E> to Result<T, E>', () => {
    const res = new Result<Result<string, Error>, Error>(new Result<string, Error>('test'))
    assert(res.flatten(), new Result('test'))
  })
});

Deno.test("Result - Supporting Function Tests", async (t) => {
  await t.step("Ok - Should return Ok result.", () => {
    const res = Ok("Test");
    assertEquals(res.isOk(), true);
    assertEquals(res.peek(), "Test");
  });

  await t.step("Ok instanceof - Should return true.", () => {
    const res = Ok("Test");
    assertEquals(res instanceof Ok, true);
  });

  await t.step("Err - Should return Error result.", () => {
    const res = Err(new Error("Test"));
    assertEquals(res.isErr(), true);
    assertEquals(res.unwrapErr().message, "Test");
  });

  await t.step("Err String - Should construct and return Error result.", () => {
    const res = Err("Test");
    assertEquals(res.isErr(), true);
    assertEquals(res.unwrapErr().message, "Test");
  });

  await t.step("Err instanceof - Should return true.", () => {
    const res = Err(new Error("Test"));
    assertEquals(res instanceof Err, true);
  });

  await t.step("from - Should return Ok result.", () => {
    const res = Result.from(() => "Test");
    assert(res.isOk());
    assertEquals(res.peek(), "Test");
  });

  await t.step("from Error - Should return Err result.", () => {
    const res = Result.from(() => {
      throw new Error("Test");
    });
    assert(res.isErr());
    assertEquals(res.peek().message, "Test");
  });

  await t.step("fromAsync - Should return Ok result.", async () => {
    const res = await Result.fromAsync(
      async () => await Promise.resolve("Test")
    );
    assert(res.isOk());
    assertEquals(res.peek(), "Test");
  });

  await t.step("fromAsync Error - Should return Err result.", async () => {
    const res = await Result.fromAsync(
      async () => await Promise.reject(new Error("Test"))
    );
    assert(res.isErr());
    assertEquals((res.peek() as Error).message, "Test");
  });

  await t.step(
    "Result.partition - Should create array or Oks and Errs",
    async () => {
      const res = await Result.partition([
        Ok("1"),
        Ok("2"),
        Err("1"),
        Err("2"),
      ]);
      assertEquals(res.ok, ["1", "2"]);
      assertEquals(res.err.length, 2);
    }
  );
});
Download .txt
gitextract_b_g0ihly/

├── .gitignore
├── .vscode/
│   └── settings.json
├── LICENSE
├── README.md
├── deno.json
├── mod.ts
├── scripts/
│   ├── build_npm.json
│   └── build_npm.ts
└── src/
    ├── option.ts
    ├── result.ts
    └── tests/
        ├── option.test.ts
        └── result.test.ts
Download .txt
SYMBOL INDEX (50 symbols across 4 files)

FILE: scripts/build_npm.ts
  function versionHandler (line 18) | function versionHandler(current: string, releaseType: ReleaseType): stri...

FILE: src/option.ts
  class Option (line 25) | class Option<T> {
    method constructor (line 35) | constructor(input: T | typeof none) {
    method isSome (line 60) | isSome(): boolean {
    method isNone (line 69) | isNone(): boolean {
    method expect (line 80) | expect(msg: string): T {
    method unwrap (line 94) | unwrap(): T {
    method unwrapOr (line 108) | unwrapOr(fallback: T): T {
    method unwrapOrElse (line 122) | unwrapOrElse(fn: () => T): T {
    method map (line 136) | map<U>(fn: (input: T) => U): Option<U> {
    method mapOr (line 150) | mapOr<U>(fallback: U, fn: (input: T) => U): U {
    method or (line 164) | or(or: Option<T>): Option<T> {
    method okOr (line 183) | okOr<E extends Error>(err: E | string): Result<T, E> {
    method peek (line 214) | peek(): T | typeof none {
    method flatten (line 222) | flatten(): Option<T> {
    method from (line 237) | static from<T>(fn: () => T | null | undefined): Option<T> {
    method fromAsync (line 254) | static async fromAsync<T>(
  method [Symbol.toStringTag] (line 42) | get [Symbol.toStringTag]() {
  method [Symbol.iterator] (line 52) | *[Symbol.iterator]() {
  function Some (line 290) | function Some<T>(input: T): Option<T> {
  function None (line 322) | function None<T>(): Option<T> {

FILE: src/result.ts
  class Result (line 21) | class Result<T, E extends Error> {
    method constructor (line 31) | constructor(input: T | E) {
    method isOk (line 57) | isOk(): boolean {
    method isErr (line 71) | isErr(): boolean {
    method formatError (line 80) | private formatError(err: Error) {
    method expect (line 97) | expect(msg: string): T {
    method expectErr (line 112) | expectErr(msg: string): T {
    method unwrap (line 126) | unwrap(): T {
    method unwrapErr (line 140) | unwrapErr(): E {
    method unwrapOr (line 156) | unwrapOr(fallback: T): T {
    method unwrapOrElse (line 170) | unwrapOrElse(fn: (input: E) => T): T {
    method map (line 184) | map<U>(fn: (input: T) => U): Result<U, E> {
    method mapErr (line 198) | mapErr<U extends Error>(fn: (input: E) => U): Result<T, U> {
    method mapOr (line 213) | mapOr<U>(fallback: U, fn: (input: T) => U): U {
    method or (line 227) | or(or: Result<T, E>): Result<T, E> {
    method ok (line 245) | ok(): Option<T> {
    method peek (line 276) | peek(): T | E {
    method throw (line 283) | throw(): void {
    method flatten (line 293) | flatten(): Result<T, E> {
    method from (line 307) | static from<T>(fn: () => T): Result<T, Error> {
    method fromAsync (line 322) | static async fromAsync<T>(fn: () => Promise<T>): Promise<Result<T, Err...
    method partition (line 344) | static partition<T, E extends Error>(
  method [Symbol.toStringTag] (line 38) | get [Symbol.toStringTag]() {
  method [Symbol.iterator] (line 48) | *[Symbol.iterator]() {
  function Ok (line 386) | function Ok<T, E extends Error>(input?: T) {
  function Err (line 421) | function Err<T, E extends Error>(input: E | string): Result<T, E> {

FILE: src/tests/result.test.ts
  class TestError (line 8) | class TestError extends Error {
  class ErrorLookAlike (line 12) | class ErrorLookAlike {
    method constructor (line 17) | constructor(message: string) {
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (41K chars).
[
  {
    "path": ".gitignore",
    "chars": 24,
    "preview": "\n.DS_Store\ncoverage\nnpm\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 134,
    "preview": "{\n    \"deno.enable\": true,\n    \"deno.lint\": true,\n    \"deno.unstable\": true,\n    \"editor.defaultFormatter\": \"esbenp.pret"
  },
  {
    "path": "LICENSE",
    "chars": 1072,
    "preview": "MIT License\n\nCopyright (c) 2021 Oliver Brotchie\n\nPermission is hereby granted, free of charge, to any person obtaining a"
  },
  {
    "path": "README.md",
    "chars": 1269,
    "preview": "<div align=\"center\">\n\n  <h1><code>Optionals</code></h1>\n\n<strong>Rust-like error handling and options for TypeScript, No"
  },
  {
    "path": "deno.json",
    "chars": 411,
    "preview": "{\n  \"tasks\": {\n    \"test\": \"deno test --coverage=coverage\",\n    \"lcov\": \"deno coverage coverage --lcov --output=coverage"
  },
  {
    "path": "mod.ts",
    "chars": 496,
    "preview": "/**\n * # `Optionals`\n *\n * **Rust-like error handling and options for TypeScript and Deno!**\n *\n * This module provides "
  },
  {
    "path": "scripts/build_npm.json",
    "chars": 623,
    "preview": "{\n  \"$schema\": \"https://json.schemastore.org/package.json\",\n  \"name\": \"rust-optionals\",\n  \"version\": \"3.0.0\",\n  \"descrip"
  },
  {
    "path": "scripts/build_npm.ts",
    "chars": 1895,
    "preview": "/*\n * Contributed 2022 by Aaron Huggins under the MIT license.\n */\nimport { parse } from \"https://deno.land/std@0.160.0/"
  },
  {
    "path": "src/option.ts",
    "chars": 7507,
    "preview": "import { Err, Ok, Result } from \"./result.ts\";\n\n/**\n * The primitive None value.\n *\n * _Note: To construct a None varian"
  },
  {
    "path": "src/result.ts",
    "chars": 9970,
    "preview": "// deno-lint-ignore-file no-prototype-builtins\n/* eslint-disable no-prototype-builtins */\n\nimport { None, Option, Some }"
  },
  {
    "path": "src/tests/option.test.ts",
    "chars": 6078,
    "preview": "import { Option, Some, None, none } from \"../option.ts\";\nimport {\n  assertEquals,\n  assert,\n  fail,\n} from \"https://deno"
  },
  {
    "path": "src/tests/result.test.ts",
    "chars": 8994,
    "preview": "import { Result, Ok, Err } from \"../result.ts\";\nimport {\n  assertEquals,\n  assert,\n  fail,\n} from \"https://deno.land/std"
  }
]

About this extraction

This page contains the full source code of the OliverBrotchie/optionals GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (37.6 KB), approximately 10.4k tokens, and a symbol index with 50 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!