mirror of
				https://github.com/SikongJueluo/cc-utils.git
				synced 2025-11-04 19:27:50 +08:00 
			
		
		
		
	reconstruct: autocraft algorithm; feature: rust-style result
reconstruct: - move queue and sortedarray to dir datatype - move semaphore and readwritelock to dir mutex - reconstruct autocraft search algorithm, use hashmap instead of forloop - adjust some code style feature: - add rust-style result lib
This commit is contained in:
		@@ -4,7 +4,7 @@ import { createAccessControlCLI } from "./cli";
 | 
			
		||||
import { launchAccessControlTUI } from "./tui";
 | 
			
		||||
import * as peripheralManager from "../lib/PeripheralManager";
 | 
			
		||||
import { deepCopy } from "@/lib/common";
 | 
			
		||||
import { ReadWriteLock } from "@/lib/ReadWriteLock";
 | 
			
		||||
import { ReadWriteLock } from "@/lib/mutex/ReadWriteLock";
 | 
			
		||||
 | 
			
		||||
const args = [...$vararg];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,60 +1,62 @@
 | 
			
		||||
import { CraftManager } from "@/lib/CraftManager";
 | 
			
		||||
import * as peripheralManager from "../lib/PeripheralManager";
 | 
			
		||||
import { CCLog } from "@/lib/ccLog";
 | 
			
		||||
 | 
			
		||||
const log = new CCLog("autocraft.log");
 | 
			
		||||
const logger = new CCLog("autocraft.log");
 | 
			
		||||
 | 
			
		||||
const peripheralsRelativeSides = {
 | 
			
		||||
const peripheralsNames = {
 | 
			
		||||
  packagesContainer: "minecraft:chest_10",
 | 
			
		||||
  itemsContainer: "minecraft:chest_9",
 | 
			
		||||
  packageExtractor: "create:packager_1",
 | 
			
		||||
  blockReader: "front",
 | 
			
		||||
  wiredModem: "back",
 | 
			
		||||
  redstone: "front",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const packagesContainer = peripheral.wrap(
 | 
			
		||||
  peripheralsNames.packagesContainer,
 | 
			
		||||
) as InventoryPeripheral;
 | 
			
		||||
const itemsContainer = peripheral.wrap(
 | 
			
		||||
  peripheralsNames.itemsContainer,
 | 
			
		||||
) as InventoryPeripheral;
 | 
			
		||||
const packageExtractor = peripheral.wrap(
 | 
			
		||||
  peripheralsNames.packageExtractor,
 | 
			
		||||
) as InventoryPeripheral;
 | 
			
		||||
const blockReader = peripheral.wrap(
 | 
			
		||||
  peripheralsNames.blockReader,
 | 
			
		||||
) as BlockReaderPeripheral;
 | 
			
		||||
const wiredModem = peripheral.wrap(
 | 
			
		||||
  peripheralsNames.wiredModem,
 | 
			
		||||
) as WiredModemPeripheral;
 | 
			
		||||
const turtleLocalName = wiredModem.getNameLocal();
 | 
			
		||||
 | 
			
		||||
enum State {
 | 
			
		||||
  IDLE,
 | 
			
		||||
  CHECK_PACK,
 | 
			
		||||
  READ_RECIPE,
 | 
			
		||||
  PULL_ITEMS,
 | 
			
		||||
  CRAFT_OUTPUT,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function main() {
 | 
			
		||||
  const packagesContainer = peripheralManager.findByNameRequired(
 | 
			
		||||
    "inventory",
 | 
			
		||||
    peripheralsRelativeSides.packagesContainer,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const itemsContainer = peripheralManager.findByNameRequired(
 | 
			
		||||
    "inventory",
 | 
			
		||||
    peripheralsRelativeSides.itemsContainer,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const packageExtractor = peripheralManager.findByNameRequired(
 | 
			
		||||
    "inventory",
 | 
			
		||||
    peripheralsRelativeSides.packageExtractor,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const blockReader = peripheralManager.findByNameRequired(
 | 
			
		||||
    "blockReader",
 | 
			
		||||
    peripheralsRelativeSides.blockReader,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const wiredModem = peripheralManager.findByNameRequired(
 | 
			
		||||
    "wiredModem",
 | 
			
		||||
    peripheralsRelativeSides.wiredModem,
 | 
			
		||||
  );
 | 
			
		||||
  const turtleLocalName = wiredModem.getNameLocal();
 | 
			
		||||
 | 
			
		||||
  const craftManager = new CraftManager(turtleLocalName);
 | 
			
		||||
  let hasPackage = redstone.getInput(peripheralsNames.redstone);
 | 
			
		||||
  // let currentState = State.IDLE;
 | 
			
		||||
  // let nextState = State.IDLE;
 | 
			
		||||
 | 
			
		||||
  let hasPackage = redstone.getInput("front");
 | 
			
		||||
  logger.info("AutoCraft init finished...");
 | 
			
		||||
  while (true) {
 | 
			
		||||
    if (!hasPackage) os.pullEvent("redstone");
 | 
			
		||||
    hasPackage = redstone.getInput("front");
 | 
			
		||||
    hasPackage = redstone.getInput(peripheralsNames.redstone);
 | 
			
		||||
    if (!hasPackage) {
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    log.info(`Package detected`);
 | 
			
		||||
    logger.info(`Package detected`);
 | 
			
		||||
 | 
			
		||||
    const itemsInfo = packagesContainer.list();
 | 
			
		||||
    for (const key in itemsInfo) {
 | 
			
		||||
      const slot = parseInt(key);
 | 
			
		||||
      const item = itemsInfo[slot];
 | 
			
		||||
      log.info(`${item.count}x ${item.name} in slot ${key}`);
 | 
			
		||||
      logger.info(`${item.count}x ${item.name} in slot ${key}`);
 | 
			
		||||
 | 
			
		||||
      // Get package NBT
 | 
			
		||||
      packagesContainer.pushItems(turtleLocalName, slot);
 | 
			
		||||
@@ -65,9 +67,9 @@ function main() {
 | 
			
		||||
      const packageRecipes = CraftManager.getPackageRecipe(packageInfo);
 | 
			
		||||
 | 
			
		||||
      // No recipe, just extract package
 | 
			
		||||
      if (packageRecipes == undefined) {
 | 
			
		||||
      if (packageRecipes.isNone()) {
 | 
			
		||||
        packageExtractor.pullItems(turtleLocalName, 1);
 | 
			
		||||
        log.info(`No recipe, just pass`);
 | 
			
		||||
        logger.info(`No recipe, just pass`);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@@ -76,7 +78,7 @@ function main() {
 | 
			
		||||
      packageExtractor.pullItems(turtleLocalName, 1);
 | 
			
		||||
 | 
			
		||||
      // Pull and craft multi recipe
 | 
			
		||||
      for (const recipe of packageRecipes) {
 | 
			
		||||
      for (const recipe of packageRecipes.value) {
 | 
			
		||||
        let craftOutputItem: BlockItemDetailData | undefined = undefined;
 | 
			
		||||
        let restCraftCnt = recipe.Count;
 | 
			
		||||
 | 
			
		||||
@@ -84,15 +86,17 @@ function main() {
 | 
			
		||||
          // Clear workbench
 | 
			
		||||
          craftManager.pushAll(itemsContainer);
 | 
			
		||||
 | 
			
		||||
          log.info(`Pull items according to a recipe`);
 | 
			
		||||
          const craftCnt = craftManager.pullItems(
 | 
			
		||||
            recipe,
 | 
			
		||||
            itemsContainer,
 | 
			
		||||
            restCraftCnt,
 | 
			
		||||
          );
 | 
			
		||||
          logger.info(`Pull items according to a recipe`);
 | 
			
		||||
          const craftCnt = craftManager
 | 
			
		||||
            .pullItems(recipe, itemsContainer, restCraftCnt)
 | 
			
		||||
            .unwrapOrElse((error) => {
 | 
			
		||||
              logger.error(error.message);
 | 
			
		||||
              return 0;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
          if (craftCnt == 0) break;
 | 
			
		||||
          craftManager.craft();
 | 
			
		||||
          log.info(`Craft ${craftCnt} times`);
 | 
			
		||||
          logger.info(`Craft ${craftCnt} times`);
 | 
			
		||||
          restCraftCnt -= craftCnt;
 | 
			
		||||
 | 
			
		||||
          // Get output item
 | 
			
		||||
@@ -101,9 +105,9 @@ function main() {
 | 
			
		||||
 | 
			
		||||
        // Finally output
 | 
			
		||||
        if (restCraftCnt > 0) {
 | 
			
		||||
          log.warn(`Only craft ${recipe.Count - restCraftCnt} times`);
 | 
			
		||||
          logger.warn(`Only craft ${recipe.Count - restCraftCnt} times`);
 | 
			
		||||
        } else {
 | 
			
		||||
          log.info(`Finish craft ${recipe.Count}x ${craftOutputItem?.id}`);
 | 
			
		||||
          logger.info(`Finish craft ${recipe.Count}x ${craftOutputItem?.id}`);
 | 
			
		||||
        }
 | 
			
		||||
        craftManager.pushAll(itemsContainer);
 | 
			
		||||
      }
 | 
			
		||||
@@ -114,7 +118,7 @@ function main() {
 | 
			
		||||
try {
 | 
			
		||||
  main();
 | 
			
		||||
} catch (error: unknown) {
 | 
			
		||||
  log.error(textutils.serialise(error as object));
 | 
			
		||||
  logger.error(textutils.serialise(error as object));
 | 
			
		||||
} finally {
 | 
			
		||||
  log.close();
 | 
			
		||||
  logger.close();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
import { CCLog } from "./ccLog";
 | 
			
		||||
 | 
			
		||||
const log = new CCLog("CraftManager.log");
 | 
			
		||||
import { Queue } from "./datatype/Queue";
 | 
			
		||||
import { Result, Ok, Err, Option, Some, None } from "./thirdparty/ts-result-es";
 | 
			
		||||
 | 
			
		||||
// ComputerCraft Turtle inventory layout:
 | 
			
		||||
// 1,  2,  3,  4
 | 
			
		||||
@@ -70,6 +69,13 @@ interface CraftRecipe {
 | 
			
		||||
  Count: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface InventorySlotInfo {
 | 
			
		||||
  name: string;
 | 
			
		||||
  count: number;
 | 
			
		||||
  maxCount: number;
 | 
			
		||||
  slotNum: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CraftMode = "keep" | "keepProduct" | "keepIngredient";
 | 
			
		||||
 | 
			
		||||
class CraftManager {
 | 
			
		||||
@@ -117,80 +123,122 @@ class CraftManager {
 | 
			
		||||
 | 
			
		||||
  public static getPackageRecipe(
 | 
			
		||||
    item: BlockItemDetailData,
 | 
			
		||||
  ): CraftRecipe[] | undefined {
 | 
			
		||||
  ): Option<CraftRecipe[]> {
 | 
			
		||||
    if (
 | 
			
		||||
      !item.id.includes("create:cardboard_package") ||
 | 
			
		||||
      (item.tag as CreatePackageTag)?.Fragment?.OrderContext
 | 
			
		||||
        ?.OrderedCrafts?.[0] == undefined
 | 
			
		||||
    ) {
 | 
			
		||||
      return undefined;
 | 
			
		||||
      return None;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const orderedCraft = (item.tag as CreatePackageTag).Fragment.OrderContext
 | 
			
		||||
      .OrderedCrafts;
 | 
			
		||||
    return orderedCraft.map((value, _) => ({
 | 
			
		||||
      PatternEntries: value.Pattern.Entries,
 | 
			
		||||
      Count: value.Count,
 | 
			
		||||
    }));
 | 
			
		||||
    return new Some(
 | 
			
		||||
      orderedCraft.map((value, _) => ({
 | 
			
		||||
        PatternEntries: value.Pattern.Entries,
 | 
			
		||||
        Count: value.Count,
 | 
			
		||||
      })),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public pullItems(
 | 
			
		||||
    recipe: CraftRecipe,
 | 
			
		||||
    inventory: InventoryPeripheral,
 | 
			
		||||
    limit: number,
 | 
			
		||||
  ): number {
 | 
			
		||||
    let maxCraftCount = limit;
 | 
			
		||||
    srcInventory: InventoryPeripheral,
 | 
			
		||||
    craftCnt: number,
 | 
			
		||||
  ): Result<number> {
 | 
			
		||||
    // Initialize hash map
 | 
			
		||||
    const ingredientList = srcInventory.list();
 | 
			
		||||
    const ingredientMap = new Map<string, Queue<InventorySlotInfo>>();
 | 
			
		||||
    for (const key in ingredientList) {
 | 
			
		||||
      const slotNum = parseInt(key);
 | 
			
		||||
      const item = srcInventory.getItemDetail(slotNum)!;
 | 
			
		||||
 | 
			
		||||
      if (ingredientMap.has(item.name)) {
 | 
			
		||||
        ingredientMap.get(item.name)!.enqueue({
 | 
			
		||||
          name: item.name,
 | 
			
		||||
          slotNum: slotNum,
 | 
			
		||||
          count: item.count,
 | 
			
		||||
          maxCount: item.maxCount,
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        ingredientMap.set(
 | 
			
		||||
          item.name,
 | 
			
		||||
          new Queue<InventorySlotInfo>([
 | 
			
		||||
            {
 | 
			
		||||
              name: item.name,
 | 
			
		||||
              slotNum: slotNum,
 | 
			
		||||
              count: item.count,
 | 
			
		||||
              maxCount: item.maxCount,
 | 
			
		||||
            },
 | 
			
		||||
          ]),
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let maxCraftCnt = craftCnt;
 | 
			
		||||
    for (const index in recipe.PatternEntries) {
 | 
			
		||||
      const entry = recipe.PatternEntries[index];
 | 
			
		||||
      if (entry.Item.Count == 0 || entry.Item.id == "minecraft:air") {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const ingredientList = inventory.list();
 | 
			
		||||
      let restCount = maxCraftCount;
 | 
			
		||||
      for (const key in ingredientList) {
 | 
			
		||||
        // Get item detail and check max count
 | 
			
		||||
        const slot = parseInt(key);
 | 
			
		||||
        const ingredient = inventory.getItemDetail(slot)!;
 | 
			
		||||
        if (entry.Item.id != ingredient.name) {
 | 
			
		||||
          continue;
 | 
			
		||||
      if (!ingredientMap.has(entry.Item.id))
 | 
			
		||||
        return new Err(Error(`No ingredient match ${entry.Item.id}`));
 | 
			
		||||
 | 
			
		||||
      const ingredient = ingredientMap.get(entry.Item.id)!;
 | 
			
		||||
      let restCraftCnt = maxCraftCnt;
 | 
			
		||||
      while (restCraftCnt > 0 && ingredient.size() > 0) {
 | 
			
		||||
        const slotItem = ingredient.dequeue()!;
 | 
			
		||||
 | 
			
		||||
        // Check item max stack count
 | 
			
		||||
        if (slotItem.maxCount < maxCraftCnt) {
 | 
			
		||||
          maxCraftCnt = slotItem.maxCount;
 | 
			
		||||
          restCraftCnt = maxCraftCnt;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const ingredientMaxCount = ingredient.maxCount;
 | 
			
		||||
        if (maxCraftCount > ingredientMaxCount) {
 | 
			
		||||
          maxCraftCount = ingredientMaxCount;
 | 
			
		||||
          restCount = maxCraftCount;
 | 
			
		||||
        }
 | 
			
		||||
        log.info(
 | 
			
		||||
          `Slot ${slot} ${ingredient.name} max count: ${ingredientMaxCount}`,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // TODO: Process multi count entry item
 | 
			
		||||
        if (ingredient.count >= restCount) {
 | 
			
		||||
          inventory.pushItems(
 | 
			
		||||
        if (slotItem.count >= restCraftCnt) {
 | 
			
		||||
          const pushItemsCnt = srcInventory.pushItems(
 | 
			
		||||
            this.localName,
 | 
			
		||||
            slot,
 | 
			
		||||
            restCount,
 | 
			
		||||
            CRAFT_SLOT_TABLE[parseInt(index) - 1],
 | 
			
		||||
            slotItem.slotNum,
 | 
			
		||||
            restCraftCnt,
 | 
			
		||||
            CRAFT_SLOT_TABLE[index],
 | 
			
		||||
          );
 | 
			
		||||
          restCount = 0;
 | 
			
		||||
          break;
 | 
			
		||||
          if (pushItemsCnt !== restCraftCnt)
 | 
			
		||||
            return new Err(
 | 
			
		||||
              Error(
 | 
			
		||||
                `Try to get items ${restCraftCnt}x "${slotItem.name}" from inventory, but only get ${pushItemsCnt}x`,
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
          if (slotItem.count > restCraftCnt) {
 | 
			
		||||
            ingredient.enqueue({
 | 
			
		||||
              ...slotItem,
 | 
			
		||||
              count: slotItem.count - restCraftCnt,
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
          restCraftCnt = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
          inventory.pushItems(
 | 
			
		||||
          const pushItemsCnt = srcInventory.pushItems(
 | 
			
		||||
            this.localName,
 | 
			
		||||
            slot,
 | 
			
		||||
            ingredient.count,
 | 
			
		||||
            CRAFT_SLOT_TABLE[parseInt(index) - 1],
 | 
			
		||||
            slotItem.slotNum,
 | 
			
		||||
            slotItem.count,
 | 
			
		||||
            CRAFT_SLOT_TABLE[index],
 | 
			
		||||
          );
 | 
			
		||||
          restCount -= ingredient.count;
 | 
			
		||||
          if (pushItemsCnt !== slotItem.count)
 | 
			
		||||
            return new Err(
 | 
			
		||||
              Error(
 | 
			
		||||
                `Try to get items ${slotItem.count}x "${slotItem.name}" from inventory, but only get ${pushItemsCnt}x`,
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
          restCraftCnt -= slotItem.count;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (restCount > 0) return 0;
 | 
			
		||||
      if (restCraftCnt > 0)
 | 
			
		||||
        return new Err(Error("Not enough items in inventory"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return maxCraftCount;
 | 
			
		||||
    return new Ok(maxCraftCnt);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ export function concatSentence(words: string[], length: number): string[] {
 | 
			
		||||
 * @see Source project, ts-deepcopy https://github.com/ykdr2017/ts-deepcopy
 | 
			
		||||
 * @see Code pen https://codepen.io/erikvullings/pen/ejyBYg
 | 
			
		||||
 */
 | 
			
		||||
export const deepCopy = <T>(target: T): T => {
 | 
			
		||||
export function deepCopy<T>(target: T): T {
 | 
			
		||||
  if (target === null) {
 | 
			
		||||
    return target;
 | 
			
		||||
  }
 | 
			
		||||
@@ -48,4 +48,4 @@ export const deepCopy = <T>(target: T): T => {
 | 
			
		||||
    return cp as T;
 | 
			
		||||
  }
 | 
			
		||||
  return target;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
export class Node<T> {
 | 
			
		||||
  public value: T;
 | 
			
		||||
  public next?: Node<T>
 | 
			
		||||
  public prev?: Node<T>
 | 
			
		||||
  public next?: Node<T>;
 | 
			
		||||
  public prev?: Node<T>;
 | 
			
		||||
 | 
			
		||||
  constructor(value: T, next?: Node<T>, prev?: Node<T>) {
 | 
			
		||||
    this.value = value;
 | 
			
		||||
@@ -15,10 +15,15 @@ export class Queue<T> {
 | 
			
		||||
  private _tail?: Node<T>;
 | 
			
		||||
  private _size: number;
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
  constructor(data?: T[]) {
 | 
			
		||||
    this._head = undefined;
 | 
			
		||||
    this._tail = undefined;
 | 
			
		||||
    this._size = 0;
 | 
			
		||||
 | 
			
		||||
    if (data === undefined) return;
 | 
			
		||||
    for (const item of data) {
 | 
			
		||||
      this.enqueue(item);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public enqueue(data: T): void {
 | 
			
		||||
@@ -37,11 +42,11 @@ export class Queue<T> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public dequeue(): T | undefined {
 | 
			
		||||
    if (this._head === undefined) return undefined;
 | 
			
		||||
    const node = this._head;
 | 
			
		||||
    if (node === undefined) return undefined;
 | 
			
		||||
 | 
			
		||||
    this._head = this._head!.next;
 | 
			
		||||
    this._head!.prev = undefined;
 | 
			
		||||
    this._head = node.next;
 | 
			
		||||
    if (this._head !== undefined) this._head.prev = undefined;
 | 
			
		||||
    this._size--;
 | 
			
		||||
 | 
			
		||||
    return node.value;
 | 
			
		||||
@@ -68,8 +73,7 @@ export class Queue<T> {
 | 
			
		||||
    const array: T[] = [];
 | 
			
		||||
    let currentNode: Node<T> = this._head!;
 | 
			
		||||
    for (let i = 0; i < this._size; i++) {
 | 
			
		||||
      if (currentNode.value !== undefined)
 | 
			
		||||
        array.push(currentNode.value);
 | 
			
		||||
      if (currentNode.value !== undefined) array.push(currentNode.value);
 | 
			
		||||
 | 
			
		||||
      currentNode = currentNode.next!;
 | 
			
		||||
    }
 | 
			
		||||
@@ -82,13 +86,13 @@ export class Queue<T> {
 | 
			
		||||
    return {
 | 
			
		||||
      next(): IteratorResult<T> {
 | 
			
		||||
        if (currentNode === undefined) {
 | 
			
		||||
          return { value: undefined, done: true }
 | 
			
		||||
          return { value: undefined, done: true };
 | 
			
		||||
        } else {
 | 
			
		||||
          const data = currentNode.value;
 | 
			
		||||
          currentNode = currentNode.next;
 | 
			
		||||
          return { value: data, done: false }
 | 
			
		||||
          return { value: data, done: false };
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { SortedArray } from "./SortedArray";
 | 
			
		||||
import { SortedArray } from "../datatype/SortedArray";
 | 
			
		||||
 | 
			
		||||
const E_CANCELED = new Error("Request canceled");
 | 
			
		||||
// const E_INSUFFICIENT_RESOURCES = new Error("Insufficient resources");
 | 
			
		||||
							
								
								
									
										21
									
								
								src/lib/thirdparty/ts-result-es/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/lib/thirdparty/ts-result-es/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2019 vultix
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
							
								
								
									
										2
									
								
								src/lib/thirdparty/ts-result-es/index.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/lib/thirdparty/ts-result-es/index.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
export * from "./result";
 | 
			
		||||
export * from "./option";
 | 
			
		||||
							
								
								
									
										343
									
								
								src/lib/thirdparty/ts-result-es/option.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								src/lib/thirdparty/ts-result-es/option.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,343 @@
 | 
			
		||||
import { toString } from "./utils";
 | 
			
		||||
// import { Result, Ok, Err } from "./result";
 | 
			
		||||
 | 
			
		||||
interface BaseOption<T> extends Iterable<T> {
 | 
			
		||||
  /** `true` when the Option is Some */
 | 
			
		||||
  isSome(): this is SomeImpl<T>;
 | 
			
		||||
 | 
			
		||||
  /** `true` when the Option is None */
 | 
			
		||||
  isNone(): this is None;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Some` value, if exists.  Throws an error if not.
 | 
			
		||||
   *
 | 
			
		||||
   * If you know you're dealing with `Some` and the compiler knows it too (because you tested
 | 
			
		||||
   * `isSome()` or `isNone()`) you should use `value` instead. While `Some`'s `expect()` and `value` will
 | 
			
		||||
   * both return the same value using `value` is preferable because it makes it clear that
 | 
			
		||||
   * there won't be an exception thrown on access.
 | 
			
		||||
   *
 | 
			
		||||
   * @param msg the message to throw if no Some value.
 | 
			
		||||
   */
 | 
			
		||||
  expect(msg: string): T;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Some` value.
 | 
			
		||||
   * Because this function may throw, its use is generally discouraged.
 | 
			
		||||
   * Instead, prefer to handle the `None` case explicitly.
 | 
			
		||||
   *
 | 
			
		||||
   * If you know you're dealing with `Some` and the compiler knows it too (because you tested
 | 
			
		||||
   * `isSome()` or `isNone()`) you should use `value` instead. While `Some`'s `unwrap()` and `value` will
 | 
			
		||||
   * both return the same value using `value` is preferable because it makes it clear that
 | 
			
		||||
   * there won't be an exception thrown on access.
 | 
			
		||||
   *
 | 
			
		||||
   * Throws if the value is `None`.
 | 
			
		||||
   */
 | 
			
		||||
  unwrap(): T;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Some` value or a provided default.
 | 
			
		||||
   *
 | 
			
		||||
   *  (This is the `unwrap_or` in rust)
 | 
			
		||||
   */
 | 
			
		||||
  unwrapOr<T2>(val: T2): T | T2;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Some` value or computes a value with a provided function.
 | 
			
		||||
   *
 | 
			
		||||
   * The function is called at most one time, only if needed.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   * ```
 | 
			
		||||
   * Some('OK').unwrapOrElse(
 | 
			
		||||
   *     () => { console.log('Called'); return 'UGH'; }
 | 
			
		||||
   * ) // => 'OK', nothing printed
 | 
			
		||||
   *
 | 
			
		||||
   * None.unwrapOrElse(() => 'UGH') // => 'UGH'
 | 
			
		||||
   * ```
 | 
			
		||||
   */
 | 
			
		||||
  unwrapOrElse<T2>(f: () => T2): T | T2;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Calls `mapper` if the Option is `Some`, otherwise returns `None`.
 | 
			
		||||
   * This function can be used for control flow based on `Option` values.
 | 
			
		||||
   */
 | 
			
		||||
  andThen<T2>(mapper: (val: T) => Option<T2>): Option<T2>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maps an `Option<T>` to `Option<U>` by applying a function to a contained `Some` value,
 | 
			
		||||
   * leaving a `None` value untouched.
 | 
			
		||||
   *
 | 
			
		||||
   * This function can be used to compose the Options of two functions.
 | 
			
		||||
   */
 | 
			
		||||
  map<U>(mapper: (val: T) => U): Option<U>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maps an `Option<T>` to `Option<U>` by either converting `T` to `U` using `mapper` (in case
 | 
			
		||||
   * of `Some`) or using the `default_` value (in case of `None`).
 | 
			
		||||
   *
 | 
			
		||||
   * If `default` is a result of a function call consider using `mapOrElse()` instead, it will
 | 
			
		||||
   * only evaluate the function when needed.
 | 
			
		||||
   */
 | 
			
		||||
  mapOr<U>(default_: U, mapper: (val: T) => U): U;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maps an `Option<T>` to `Option<U>` by either converting `T` to `U` using `mapper` (in case
 | 
			
		||||
   * of `Some`) or producing a default value using the `default` function (in case of `None`).
 | 
			
		||||
   */
 | 
			
		||||
  mapOrElse<U>(default_: () => U, mapper: (val: T) => U): U;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns `Some()` if we have a value, otherwise returns `other`.
 | 
			
		||||
   *
 | 
			
		||||
   * `other` is evaluated eagerly. If `other` is a result of a function
 | 
			
		||||
   * call try `orElse()` instead – it evaluates the parameter lazily.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   *
 | 
			
		||||
   * Some(1).or(Some(2)) // => Some(1)
 | 
			
		||||
   * None.or(Some(2)) // => Some(2)
 | 
			
		||||
   */
 | 
			
		||||
  or(other: Option<T>): Option<T>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns `Some()` if we have a value, otherwise returns the result
 | 
			
		||||
   * of calling `other()`.
 | 
			
		||||
   *
 | 
			
		||||
   * `other()` is called *only* when needed.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   *
 | 
			
		||||
   * Some(1).orElse(() => Some(2)) // => Some(1)
 | 
			
		||||
   * None.orElse(() => Some(2)) // => Some(2)
 | 
			
		||||
   */
 | 
			
		||||
  orElse(other: () => Option<T>): Option<T>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maps an `Option<T>` to a `Result<T, E>`.
 | 
			
		||||
   */
 | 
			
		||||
  // toResult<E>(error: E): Result<T, E>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains the None value
 | 
			
		||||
 */
 | 
			
		||||
class NoneImpl implements BaseOption<never> {
 | 
			
		||||
  isSome(): this is SomeImpl<never> {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isNone(): this is NoneImpl {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  [Symbol.iterator](): Iterator<never, never, unknown> {
 | 
			
		||||
    return {
 | 
			
		||||
      next(): IteratorResult<never, never> {
 | 
			
		||||
        return { done: true, value: undefined! };
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapOr<T2>(val: T2): T2 {
 | 
			
		||||
    return val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapOrElse<T2>(f: () => T2): T2 {
 | 
			
		||||
    return f();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  expect(msg: string): never {
 | 
			
		||||
    throw new Error(`${msg}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrap(): never {
 | 
			
		||||
    throw new Error(`Tried to unwrap None`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  map(_mapper: unknown): None {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapOr<T2>(default_: T2, _mapper: unknown): T2 {
 | 
			
		||||
    return default_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapOrElse<U>(default_: () => U, _mapper: unknown): U {
 | 
			
		||||
    return default_();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  or<T>(other: Option<T>): Option<T> {
 | 
			
		||||
    return other;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  orElse<T>(other: () => Option<T>): Option<T> {
 | 
			
		||||
    return other();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  andThen(_op: unknown): None {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // toResult<E>(error: E): Err<E> {
 | 
			
		||||
  //   return Err(error);
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  toString(): string {
 | 
			
		||||
    return "None";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Export None as a singleton, then freeze it so it can't be modified
 | 
			
		||||
export const None = new NoneImpl();
 | 
			
		||||
export type None = NoneImpl;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains the success value
 | 
			
		||||
 */
 | 
			
		||||
class SomeImpl<T> implements BaseOption<T> {
 | 
			
		||||
  static readonly EMPTY = new SomeImpl<void>(undefined);
 | 
			
		||||
 | 
			
		||||
  isSome(): this is SomeImpl<T> {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isNone(): this is NoneImpl {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  readonly value!: T;
 | 
			
		||||
 | 
			
		||||
  [Symbol.iterator](): Iterator<T> {
 | 
			
		||||
    return [this.value][Symbol.iterator]();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(val: T) {
 | 
			
		||||
    if (!(this instanceof SomeImpl)) {
 | 
			
		||||
      return new SomeImpl(val);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.value = val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapOr(_val: unknown): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapOrElse(_f: unknown): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  expect(_msg: string): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrap(): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  map<T2>(mapper: (val: T) => T2): Some<T2> {
 | 
			
		||||
    return new Some(mapper(this.value));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapOr<T2>(_default_: T2, mapper: (val: T) => T2): T2 {
 | 
			
		||||
    return mapper(this.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapOrElse<U>(_default_: () => U, mapper: (val: T) => U): U {
 | 
			
		||||
    return mapper(this.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  or(_other: Option<T>): Option<T> {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  orElse(_other: () => Option<T>): Option<T> {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  andThen<T2>(mapper: (val: T) => Option<T2>): Option<T2> {
 | 
			
		||||
    return mapper(this.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // toResult<E>(_error: E): Ok<T> {
 | 
			
		||||
  //   return Ok(this.value);
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Some` value, but never throws.
 | 
			
		||||
   * Unlike `unwrap()`, this method doesn't throw and is only callable on an Some<T>
 | 
			
		||||
   *
 | 
			
		||||
   * Therefore, it can be used instead of `unwrap()` as a maintainability safeguard
 | 
			
		||||
   * that will fail to compile if the type of the Option is later changed to a None that can actually occur.
 | 
			
		||||
   *
 | 
			
		||||
   * (this is the `into_Some()` in rust)
 | 
			
		||||
   */
 | 
			
		||||
  safeUnwrap(): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toString(): string {
 | 
			
		||||
    return `Some(${toString(this.value)})`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This allows Some to be callable - possible because of the es5 compilation target
 | 
			
		||||
// export const Some = SomeImpl as typeof SomeImpl & (<T>(val: T) => SomeImpl<T>);
 | 
			
		||||
export const Some = SomeImpl;
 | 
			
		||||
export type Some<T> = SomeImpl<T>;
 | 
			
		||||
 | 
			
		||||
export type Option<T> = Some<T> | None;
 | 
			
		||||
 | 
			
		||||
export type OptionSomeType<T extends Option<unknown>> =
 | 
			
		||||
  T extends Some<infer U> ? U : never;
 | 
			
		||||
 | 
			
		||||
export type OptionSomeTypes<T extends Option<unknown>[]> = {
 | 
			
		||||
  [key in keyof T]: T[key] extends Option<unknown>
 | 
			
		||||
    ? OptionSomeType<T[key]>
 | 
			
		||||
    : never;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export namespace Option {
 | 
			
		||||
  /**
 | 
			
		||||
   * Parse a set of `Option`s, returning an array of all `Some` values.
 | 
			
		||||
   * Short circuits with the first `None` found, if any
 | 
			
		||||
   */
 | 
			
		||||
  export function all<T extends Option<any>[]>(
 | 
			
		||||
    ...options: T
 | 
			
		||||
  ): Option<OptionSomeTypes<T>> {
 | 
			
		||||
    const someOption: unknown[] = [];
 | 
			
		||||
    for (let option of options) {
 | 
			
		||||
      if (option.isSome()) {
 | 
			
		||||
        someOption.push(option.value);
 | 
			
		||||
      } else {
 | 
			
		||||
        return option as None;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return new Some(someOption as OptionSomeTypes<T>);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Parse a set of `Option`s, short-circuits when an input value is `Some`.
 | 
			
		||||
   * If no `Some` is found, returns `None`.
 | 
			
		||||
   */
 | 
			
		||||
  export function any<T extends Option<any>[]>(
 | 
			
		||||
    ...options: T
 | 
			
		||||
  ): Option<OptionSomeTypes<T>[number]> {
 | 
			
		||||
    // short-circuits
 | 
			
		||||
    for (const option of options) {
 | 
			
		||||
      if (option.isSome()) {
 | 
			
		||||
        return option as Some<OptionSomeTypes<T>[number]>;
 | 
			
		||||
      } else {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // it must be None
 | 
			
		||||
    return None;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  export function isOption<T = any>(value: unknown): value is Option<T> {
 | 
			
		||||
    return value instanceof Some || value === None;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										536
									
								
								src/lib/thirdparty/ts-result-es/result.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										536
									
								
								src/lib/thirdparty/ts-result-es/result.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,536 @@
 | 
			
		||||
import { toString } from "./utils";
 | 
			
		||||
// import { Option, None, Some } from "./option";
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Missing Rust Result type methods:
 | 
			
		||||
 * pub fn contains<U>(&self, x: &U) -> bool
 | 
			
		||||
 * pub fn contains_err<F>(&self, f: &F) -> bool
 | 
			
		||||
 * pub fn and<U>(self, res: Result<U, E>) -> Result<U, E>
 | 
			
		||||
 * pub fn expect_err(self, msg: &str) -> E
 | 
			
		||||
 * pub fn unwrap_or_default(self) -> T
 | 
			
		||||
 */
 | 
			
		||||
interface BaseResult<T, E> extends Iterable<T> {
 | 
			
		||||
  /** `true` when the result is Ok */
 | 
			
		||||
  isOk(): this is OkImpl<T>;
 | 
			
		||||
 | 
			
		||||
  /** `true` when the result is Err */
 | 
			
		||||
  isErr(): this is ErrImpl<E>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Ok` value, if exists.  Throws an error if not.
 | 
			
		||||
   *
 | 
			
		||||
   * The thrown error's
 | 
			
		||||
   * [`cause'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause)
 | 
			
		||||
   * is set to value contained in `Err`.
 | 
			
		||||
   *
 | 
			
		||||
   * If you know you're dealing with `Ok` and the compiler knows it too (because you tested
 | 
			
		||||
   * `isOk()` or `isErr()`) you should use `value` instead. While `Ok`'s `expect()` and `value` will
 | 
			
		||||
   * both return the same value using `value` is preferable because it makes it clear that
 | 
			
		||||
   * there won't be an exception thrown on access.
 | 
			
		||||
   *
 | 
			
		||||
   * @param msg the message to throw if no Ok value.
 | 
			
		||||
   */
 | 
			
		||||
  expect(msg: string): T;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Err` value, if exists.  Throws an error if not.
 | 
			
		||||
   * @param msg the message to throw if no Err value.
 | 
			
		||||
   */
 | 
			
		||||
  expectErr(msg: string): E;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Ok` value.
 | 
			
		||||
   * Because this function may throw, its use is generally discouraged.
 | 
			
		||||
   * Instead, prefer to handle the `Err` case explicitly.
 | 
			
		||||
   *
 | 
			
		||||
   * If you know you're dealing with `Ok` and the compiler knows it too (because you tested
 | 
			
		||||
   * `isOk()` or `isErr()`) you should use `value` instead. While `Ok`'s `unwrap()` and `value` will
 | 
			
		||||
   * both return the same value using `value` is preferable because it makes it clear that
 | 
			
		||||
   * there won't be an exception thrown on access.
 | 
			
		||||
   *
 | 
			
		||||
   * Throws if the value is an `Err`, with a message provided by the `Err`'s value and
 | 
			
		||||
   * [`cause'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause)
 | 
			
		||||
   * set to the value.
 | 
			
		||||
   */
 | 
			
		||||
  unwrap(): T;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Err` value.
 | 
			
		||||
   * Because this function may throw, its use is generally discouraged.
 | 
			
		||||
   * Instead, prefer to handle the `Ok` case explicitly and access the `error` property
 | 
			
		||||
   * directly.
 | 
			
		||||
   *
 | 
			
		||||
   * Throws if the value is an `Ok`, with a message provided by the `Ok`'s value and
 | 
			
		||||
   * [`cause'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause)
 | 
			
		||||
   * set to the value.
 | 
			
		||||
   */
 | 
			
		||||
  unwrapErr(): E;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Ok` value or a provided default.
 | 
			
		||||
   *
 | 
			
		||||
   *  @see unwrapOr
 | 
			
		||||
   *  @deprecated in favor of unwrapOr
 | 
			
		||||
   */
 | 
			
		||||
  else<T2>(val: T2): T | T2;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Ok` value or a provided default.
 | 
			
		||||
   *
 | 
			
		||||
   *  (This is the `unwrap_or` in rust)
 | 
			
		||||
   */
 | 
			
		||||
  unwrapOr<T2>(val: T2): T | T2;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Ok` value or computes a value with a provided function.
 | 
			
		||||
   *
 | 
			
		||||
   * The function is called at most one time, only if needed.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   * ```
 | 
			
		||||
   * Ok('OK').unwrapOrElse(
 | 
			
		||||
   *     (error) => { console.log(`Called, got ${error}`); return 'UGH'; }
 | 
			
		||||
   * ) // => 'OK', nothing printed
 | 
			
		||||
   *
 | 
			
		||||
   * Err('A03B').unwrapOrElse((error) => `UGH, got ${error}`) // => 'UGH, got A03B'
 | 
			
		||||
   * ```
 | 
			
		||||
   */
 | 
			
		||||
  unwrapOrElse<T2>(f: (error: E) => T2): T | T2;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Calls `mapper` if the result is `Ok`, otherwise returns the `Err` value of self.
 | 
			
		||||
   * This function can be used for control flow based on `Result` values.
 | 
			
		||||
   */
 | 
			
		||||
  andThen<T2, E2>(mapper: (val: T) => Result<T2, E2>): Result<T2, E | E2>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a contained `Ok` value,
 | 
			
		||||
   * leaving an `Err` value untouched.
 | 
			
		||||
   *
 | 
			
		||||
   * This function can be used to compose the results of two functions.
 | 
			
		||||
   */
 | 
			
		||||
  map<U>(mapper: (val: T) => U): Result<U, E>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a contained `Err` value,
 | 
			
		||||
   * leaving an `Ok` value untouched.
 | 
			
		||||
   *
 | 
			
		||||
   * This function can be used to pass through a successful result while handling an error.
 | 
			
		||||
   */
 | 
			
		||||
  mapErr<F>(mapper: (val: E) => F): Result<T, F>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maps a `Result<T, E>` to `Result<U, E>` by either converting `T` to `U` using `mapper`
 | 
			
		||||
   * (in case of `Ok`) or using the `default_` value (in case of `Err`).
 | 
			
		||||
   *
 | 
			
		||||
   * If `default` is a result of a function call consider using `mapOrElse` instead, it will
 | 
			
		||||
   * only evaluate the function when needed.
 | 
			
		||||
   */
 | 
			
		||||
  mapOr<U>(default_: U, mapper: (val: T) => U): U;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Maps a `Result<T, E>` to `Result<U, E>` by either converting `T` to `U` using `mapper`
 | 
			
		||||
   * (in case of `Ok`) or producing a default value using the `default` function (in case of
 | 
			
		||||
   * `Err`).
 | 
			
		||||
   */
 | 
			
		||||
  mapOrElse<U>(default_: (error: E) => U, mapper: (val: T) => U): U;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns `Ok()` if we have a value, otherwise returns `other`.
 | 
			
		||||
   *
 | 
			
		||||
   * `other` is evaluated eagerly. If `other` is a result of a function
 | 
			
		||||
   * call try `orElse()` instead – it evaluates the parameter lazily.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   *
 | 
			
		||||
   * Ok(1).or(Ok(2)) // => Ok(1)
 | 
			
		||||
   * Err('error here').or(Ok(2)) // => Ok(2)
 | 
			
		||||
   */
 | 
			
		||||
  or<E2>(other: Result<T, E2>): Result<T, E2>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns `Ok()` if we have a value, otherwise returns the result
 | 
			
		||||
   * of calling `other()`.
 | 
			
		||||
   *
 | 
			
		||||
   * `other()` is called *only* when needed and is passed the error value in a parameter.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   *
 | 
			
		||||
   * Ok(1).orElse(() => Ok(2)) // => Ok(1)
 | 
			
		||||
   * Err('error').orElse(() => Ok(2)) // => Ok(2)
 | 
			
		||||
   */
 | 
			
		||||
  orElse<T2, E2>(other: (error: E) => Result<T2, E2>): Result<T | T2, E2>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   *  Converts from `Result<T, E>` to `Option<T>`, discarding the error if any
 | 
			
		||||
   *
 | 
			
		||||
   *  Similar to rust's `ok` method
 | 
			
		||||
   */
 | 
			
		||||
  // toOption(): Option<T>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains the error value
 | 
			
		||||
 */
 | 
			
		||||
export class ErrImpl<E> implements BaseResult<never, E> {
 | 
			
		||||
  /** An empty Err */
 | 
			
		||||
  static readonly EMPTY = new ErrImpl<void>(undefined);
 | 
			
		||||
 | 
			
		||||
  isOk(): this is OkImpl<never> {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isErr(): this is ErrImpl<E> {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  readonly error!: E;
 | 
			
		||||
 | 
			
		||||
  private readonly _stack!: string;
 | 
			
		||||
 | 
			
		||||
  [Symbol.iterator](): Iterator<never, never, unknown> {
 | 
			
		||||
    return {
 | 
			
		||||
      next(): IteratorResult<never, never> {
 | 
			
		||||
        return { done: true, value: undefined! };
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(val: E) {
 | 
			
		||||
    if (!(this instanceof ErrImpl)) {
 | 
			
		||||
      return new ErrImpl(val);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.error = val;
 | 
			
		||||
 | 
			
		||||
    const stackLines = new Error().stack!.split("\n").slice(2);
 | 
			
		||||
    if (
 | 
			
		||||
      stackLines !== undefined &&
 | 
			
		||||
      stackLines.length > 0 &&
 | 
			
		||||
      stackLines[0].includes("ErrImpl")
 | 
			
		||||
    ) {
 | 
			
		||||
      stackLines.shift();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._stack = stackLines.join("\n");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @deprecated in favor of unwrapOr
 | 
			
		||||
   * @see unwrapOr
 | 
			
		||||
   */
 | 
			
		||||
  else<T2>(val: T2): T2 {
 | 
			
		||||
    return val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapOr<T2>(val: T2): T2 {
 | 
			
		||||
    return val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapOrElse<T2>(f: (error: E) => T2): T2 {
 | 
			
		||||
    return f(this.error);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  expect(msg: string): never {
 | 
			
		||||
    // The cause casting required because of the current TS definition being overly restrictive
 | 
			
		||||
    // (the definition says it has to be an Error while it can be anything).
 | 
			
		||||
    // See https://github.com/microsoft/TypeScript/issues/45167
 | 
			
		||||
    throw new Error(`${msg} - Error: ${toString(this.error)}\n${this._stack}`, {
 | 
			
		||||
      cause: this.error as unknown,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  expectErr(_msg: string): E {
 | 
			
		||||
    return this.error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrap(): never {
 | 
			
		||||
    // The cause casting required because of the current TS definition being overly restrictive
 | 
			
		||||
    // (the definition says it has to be an Error while it can be anything).
 | 
			
		||||
    // See https://github.com/microsoft/TypeScript/issues/45167
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      `Tried to unwrap Error: ${toString(this.error)}\n${this._stack}`,
 | 
			
		||||
      { cause: this.error as unknown },
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapErr(): E {
 | 
			
		||||
    return this.error;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  map(_mapper: unknown): Err<E> {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  andThen<T2, E2>(_op: (val: never) => Result<T2, E2>): Result<T2, E | E2> {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapErr<E2>(mapper: (err: E) => E2): Err<E2> {
 | 
			
		||||
    return new Err(mapper(this.error));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapOr<U>(default_: U, _mapper: unknown): U {
 | 
			
		||||
    return default_;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapOrElse<U>(default_: (error: E) => U, _mapper: unknown): U {
 | 
			
		||||
    return default_(this.error);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  or<T>(other: Ok<T>): Result<T, never>;
 | 
			
		||||
  or<R extends Result<unknown, unknown>>(other: R): R;
 | 
			
		||||
  or<T, E2>(other: Result<T, E2>): Result<T, E2> {
 | 
			
		||||
    return other;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  orElse<T2, E2>(other: (error: E) => Result<T2, E2>): Result<T2, E2> {
 | 
			
		||||
    return other(this.error);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // toOption(): Option<never> {
 | 
			
		||||
  //   return None;
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  toString(): string {
 | 
			
		||||
    return `Err(${toString(this.error)})`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get stack(): string | undefined {
 | 
			
		||||
    return `${this.toString()}\n${this._stack}`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This allows Err to be callable - possible because of the es5 compilation target
 | 
			
		||||
// export const Err = ErrImpl as typeof ErrImpl & (<E>(err: E) => Err<E>);
 | 
			
		||||
export const Err = ErrImpl;
 | 
			
		||||
export type Err<E> = ErrImpl<E>;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains the success value
 | 
			
		||||
 */
 | 
			
		||||
export class OkImpl<T> implements BaseResult<T, never> {
 | 
			
		||||
  static readonly EMPTY = new OkImpl<void>(undefined);
 | 
			
		||||
 | 
			
		||||
  isOk(): this is OkImpl<T> {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isErr(): this is ErrImpl<never> {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  readonly value!: T;
 | 
			
		||||
 | 
			
		||||
  [Symbol.iterator](): Iterator<T> {
 | 
			
		||||
    return [this.value][Symbol.iterator]();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(val: T) {
 | 
			
		||||
    if (!(this instanceof OkImpl)) {
 | 
			
		||||
      return new OkImpl(val);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.value = val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @see unwrapOr
 | 
			
		||||
   * @deprecated in favor of unwrapOr
 | 
			
		||||
   */
 | 
			
		||||
  else(_val: unknown): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapOr(_val: unknown): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapOrElse(_f: unknown): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  expect(_msg: string): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  expectErr(msg: string): never {
 | 
			
		||||
    throw new Error(msg);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrap(): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unwrapErr(): never {
 | 
			
		||||
    // The cause casting required because of the current TS definition being overly restrictive
 | 
			
		||||
    // (the definition says it has to be an Error while it can be anything).
 | 
			
		||||
    // See https://github.com/microsoft/TypeScript/issues/45167
 | 
			
		||||
    throw new Error(`Tried to unwrap Ok: ${toString(this.value)}`, {
 | 
			
		||||
      cause: this.value as unknown,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  map<T2>(mapper: (val: T) => T2): Ok<T2> {
 | 
			
		||||
    return new Ok(mapper(this.value));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  andThen<T2, E2>(mapper: (val: T) => Result<T2, E2>): Result<T2, E2> {
 | 
			
		||||
    return mapper(this.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapErr(_mapper: unknown): Ok<T> {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapOr<U>(_default_: U, mapper: (val: T) => U): U {
 | 
			
		||||
    return mapper(this.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mapOrElse<U>(_default_: (_error: never) => U, mapper: (val: T) => U): U {
 | 
			
		||||
    return mapper(this.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  or(_other: Result<T, unknown>): Ok<T> {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  orElse<T2, E2>(_other: (error: never) => Result<T2, E2>): Result<T, never> {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // toOption(): Option<T> {
 | 
			
		||||
  //   return Some(this.value);
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Returns the contained `Ok` value, but never throws.
 | 
			
		||||
   * Unlike `unwrap()`, this method doesn't throw and is only callable on an Ok<T>
 | 
			
		||||
   *
 | 
			
		||||
   * Therefore, it can be used instead of `unwrap()` as a maintainability safeguard
 | 
			
		||||
   * that will fail to compile if the error type of the Result is later changed to an error that can actually occur.
 | 
			
		||||
   *
 | 
			
		||||
   * (this is the `into_ok()` in rust)
 | 
			
		||||
   */
 | 
			
		||||
  safeUnwrap(): T {
 | 
			
		||||
    return this.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toString(): string {
 | 
			
		||||
    return `Ok(${toString(this.value)})`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This allows Ok to be callable - possible because of the es5 compilation target
 | 
			
		||||
// export const Ok = OkImpl as typeof OkImpl & (<T>(val: T) => Ok<T>);
 | 
			
		||||
export const Ok = OkImpl;
 | 
			
		||||
export type Ok<T> = OkImpl<T>;
 | 
			
		||||
 | 
			
		||||
export type Result<T, E = Error> = Ok<T> | Err<E>;
 | 
			
		||||
 | 
			
		||||
export type ResultOkType<T extends Result<unknown, unknown>> =
 | 
			
		||||
  T extends Ok<infer U> ? U : never;
 | 
			
		||||
export type ResultErrType<T> = T extends Err<infer U> ? U : never;
 | 
			
		||||
 | 
			
		||||
export type ResultOkTypes<T extends Result<unknown, unknown>[]> = {
 | 
			
		||||
  [key in keyof T]: T[key] extends Result<infer _U, unknown>
 | 
			
		||||
    ? ResultOkType<T[key]>
 | 
			
		||||
    : never;
 | 
			
		||||
};
 | 
			
		||||
export type ResultErrTypes<T extends Result<unknown, unknown>[]> = {
 | 
			
		||||
  [key in keyof T]: T[key] extends Result<infer _U, unknown>
 | 
			
		||||
    ? ResultErrType<T[key]>
 | 
			
		||||
    : never;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export namespace Result {
 | 
			
		||||
  /**
 | 
			
		||||
   * Parse a set of `Result`s, returning an array of all `Ok` values.
 | 
			
		||||
   * Short circuits with the first `Err` found, if any
 | 
			
		||||
   */
 | 
			
		||||
  export function all<const T extends Result<any, any>[]>(
 | 
			
		||||
    results: T,
 | 
			
		||||
  ): Result<ResultOkTypes<T>, ResultErrTypes<T>[number]> {
 | 
			
		||||
    const okResult: unknown[] = [];
 | 
			
		||||
    for (let result of results) {
 | 
			
		||||
      if (result.isOk()) {
 | 
			
		||||
        okResult.push(result.value);
 | 
			
		||||
      } else {
 | 
			
		||||
        return result as Err<ResultErrTypes<T>[number]>;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return new Ok(okResult as ResultOkTypes<T>);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Parse a set of `Result`s, short-circuits when an input value is `Ok`.
 | 
			
		||||
   * If no `Ok` is found, returns an `Err` containing the collected error values
 | 
			
		||||
   */
 | 
			
		||||
  export function any<const T extends Result<any, any>[]>(
 | 
			
		||||
    results: T,
 | 
			
		||||
  ): Result<ResultOkTypes<T>[number], ResultErrTypes<T>> {
 | 
			
		||||
    const errResult: unknown[] = [];
 | 
			
		||||
 | 
			
		||||
    // short-circuits
 | 
			
		||||
    for (const result of results) {
 | 
			
		||||
      if (result.isOk()) {
 | 
			
		||||
        return result as Ok<ResultOkTypes<T>[number]>;
 | 
			
		||||
      } else {
 | 
			
		||||
        errResult.push(result.error);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // it must be a Err
 | 
			
		||||
    return new Err(errResult as ResultErrTypes<T>);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Wrap an operation that may throw an Error (`try-catch` style) into checked exception style
 | 
			
		||||
   * @param op The operation function
 | 
			
		||||
   */
 | 
			
		||||
  export function wrap<T, E = unknown>(op: () => T): Result<T, E> {
 | 
			
		||||
    try {
 | 
			
		||||
      return new Ok(op());
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      return new Err<E>(e as E);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Wrap an async operation that may throw an Error (`try-catch` style) into checked exception style
 | 
			
		||||
   * @param op The operation function
 | 
			
		||||
   */
 | 
			
		||||
  export function wrapAsync<T, E = unknown>(
 | 
			
		||||
    op: () => Promise<T>,
 | 
			
		||||
  ): Promise<Result<T, E>> {
 | 
			
		||||
    try {
 | 
			
		||||
      return op()
 | 
			
		||||
        .then((val) => new Ok(val))
 | 
			
		||||
        .catch((e) => new Err(e));
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      return Promise.resolve(new Err(e as E));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Partitions a set of results, separating the `Ok` and `Err` values.
 | 
			
		||||
   */
 | 
			
		||||
  export function partition<T extends Result<any, any>[]>(
 | 
			
		||||
    results: T,
 | 
			
		||||
  ): [ResultOkTypes<T>, ResultErrTypes<T>] {
 | 
			
		||||
    return results.reduce(
 | 
			
		||||
      ([oks, errors], v) =>
 | 
			
		||||
        v.isOk()
 | 
			
		||||
          ? [[...oks, v.value] as ResultOkTypes<T>, errors]
 | 
			
		||||
          : [oks, [...errors, v.error] as ResultErrTypes<T>],
 | 
			
		||||
      [[], []] as [ResultOkTypes<T>, ResultErrTypes<T>],
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  export function isResult<T = any, E = any>(
 | 
			
		||||
    val: unknown,
 | 
			
		||||
  ): val is Result<T, E> {
 | 
			
		||||
    return val instanceof Err || val instanceof Ok;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								src/lib/thirdparty/ts-result-es/utils.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/lib/thirdparty/ts-result-es/utils.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
export function toString(val: unknown): string {
 | 
			
		||||
  let value = String(val);
 | 
			
		||||
  if (value === "[object Object]") {
 | 
			
		||||
    try {
 | 
			
		||||
      value = textutils.serialize(val as object);
 | 
			
		||||
    } catch {
 | 
			
		||||
      return "";
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user