From 1f2ea8b7e5568198e4185091e287197272ed8f17 Mon Sep 17 00:00:00 2001 From: didier amyot Date: Sat, 10 Jun 2023 09:33:04 -0400 Subject: [PATCH] Added test package in nix flake to automatically run tests. To be able to do such, it was required to add the vendor directory to the git project. --- flake.nix | 18 + vendor/deno.land/std@0.191.0/fmt/colors.ts | 570 +++++++++++ .../deno.land/std@0.191.0/streams/_common.ts | 26 + .../std@0.191.0/streams/iterate_reader.ts | 102 ++ vendor/deno.land/std@0.191.0/testing/_diff.ts | 440 +++++++++ .../deno.land/std@0.191.0/testing/_format.ts | 23 + .../deno.land/std@0.191.0/testing/asserts.ts | 917 ++++++++++++++++++ vendor/deno.land/std@0.191.0/types.d.ts | 90 ++ vendor/deno.land/x/base64@v0.2.1/base.ts | 136 +++ vendor/deno.land/x/base64@v0.2.1/base64url.ts | 17 + vendor/deno.land/x/base64@v0.2.1/mod.ts | 21 + .../chiefbiiko/sha1@master/deps.ts | 4 + .../denopkg.com/chiefbiiko/sha1@master/mod.ts | 191 ++++ .../chiefbiiko/std-encoding@v1.1.1/mod.ts | 56 ++ vendor/import_map.json | 8 + 15 files changed, 2619 insertions(+) create mode 100644 vendor/deno.land/std@0.191.0/fmt/colors.ts create mode 100644 vendor/deno.land/std@0.191.0/streams/_common.ts create mode 100644 vendor/deno.land/std@0.191.0/streams/iterate_reader.ts create mode 100644 vendor/deno.land/std@0.191.0/testing/_diff.ts create mode 100644 vendor/deno.land/std@0.191.0/testing/_format.ts create mode 100644 vendor/deno.land/std@0.191.0/testing/asserts.ts create mode 100644 vendor/deno.land/std@0.191.0/types.d.ts create mode 100644 vendor/deno.land/x/base64@v0.2.1/base.ts create mode 100644 vendor/deno.land/x/base64@v0.2.1/base64url.ts create mode 100644 vendor/deno.land/x/base64@v0.2.1/mod.ts create mode 100644 vendor/denopkg.com/chiefbiiko/sha1@master/deps.ts create mode 100644 vendor/denopkg.com/chiefbiiko/sha1@master/mod.ts create mode 100644 vendor/denopkg.com/chiefbiiko/std-encoding@v1.1.1/mod.ts create mode 100644 vendor/import_map.json diff --git a/flake.nix b/flake.nix index b795ec9..ad8928d 100644 --- a/flake.nix +++ b/flake.nix @@ -10,7 +10,25 @@ flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; + test-command = ''deno test --unstable --allow-read=tests .''; + test = pkgs.stdenv.mkDerivation { + name = "test"; + src = ./.; + buildInputs = [pkgs.deno]; + buildPhase = '' + export DENO_DIR=`$tmp` + deno test --import-map vendor/import_map.json --unstable --allow-read=tests . > test_results.txt + ''; + installPhase = '' + mv test_results.txt $out + ''; + + + }; in { + packages = { + test = test; + }; devShells.default = pkgs.mkShell { buildInputs = with pkgs; [deno psrecord]; diff --git a/vendor/deno.land/std@0.191.0/fmt/colors.ts b/vendor/deno.land/std@0.191.0/fmt/colors.ts new file mode 100644 index 0000000..b942a91 --- /dev/null +++ b/vendor/deno.land/std@0.191.0/fmt/colors.ts @@ -0,0 +1,570 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. +// A module to print ANSI terminal colors. Inspired by chalk, kleur, and colors +// on npm. + +/** + * String formatters and utilities for dealing with ANSI color codes. + * + * This module is browser compatible. + * + * This module supports `NO_COLOR` environmental variable disabling any coloring + * if `NO_COLOR` is set. + * + * @example + * ```typescript + * import { + * bgBlue, + * bgRgb24, + * bgRgb8, + * bold, + * italic, + * red, + * rgb24, + * rgb8, + * } from "https://deno.land/std@$STD_VERSION/fmt/colors.ts"; + * + * console.log(bgBlue(italic(red(bold("Hello, World!"))))); + * + * // also supports 8bit colors + * + * console.log(rgb8("Hello, World!", 42)); + * + * console.log(bgRgb8("Hello, World!", 42)); + * + * // and 24bit rgb + * + * console.log(rgb24("Hello, World!", { + * r: 41, + * g: 42, + * b: 43, + * })); + * + * console.log(bgRgb24("Hello, World!", { + * r: 41, + * g: 42, + * b: 43, + * })); + * ``` + * + * @module + */ + +// deno-lint-ignore no-explicit-any +const { Deno } = globalThis as any; +const noColor = typeof Deno?.noColor === "boolean" + ? Deno.noColor as boolean + : true; + +interface Code { + open: string; + close: string; + regexp: RegExp; +} + +/** RGB 8-bits per channel. Each in range `0->255` or `0x00->0xff` */ +interface Rgb { + r: number; + g: number; + b: number; +} + +let enabled = !noColor; + +/** + * Set changing text color to enabled or disabled + * @param value + */ +export function setColorEnabled(value: boolean) { + if (noColor) { + return; + } + + enabled = value; +} + +/** Get whether text color change is enabled or disabled. */ +export function getColorEnabled(): boolean { + return enabled; +} + +/** + * Builds color code + * @param open + * @param close + */ +function code(open: number[], close: number): Code { + return { + open: `\x1b[${open.join(";")}m`, + close: `\x1b[${close}m`, + regexp: new RegExp(`\\x1b\\[${close}m`, "g"), + }; +} + +/** + * Applies color and background based on color code and its associated text + * @param str text to apply color settings to + * @param code color code to apply + */ +function run(str: string, code: Code): string { + return enabled + ? `${code.open}${str.replace(code.regexp, code.open)}${code.close}` + : str; +} + +/** + * Reset the text modified + * @param str text to reset + */ +export function reset(str: string): string { + return run(str, code([0], 0)); +} + +/** + * Make the text bold. + * @param str text to make bold + */ +export function bold(str: string): string { + return run(str, code([1], 22)); +} + +/** + * The text emits only a small amount of light. + * @param str text to dim + */ +export function dim(str: string): string { + return run(str, code([2], 22)); +} + +/** + * Make the text italic. + * @param str text to make italic + */ +export function italic(str: string): string { + return run(str, code([3], 23)); +} + +/** + * Make the text underline. + * @param str text to underline + */ +export function underline(str: string): string { + return run(str, code([4], 24)); +} + +/** + * Invert background color and text color. + * @param str text to invert its color + */ +export function inverse(str: string): string { + return run(str, code([7], 27)); +} + +/** + * Make the text hidden. + * @param str text to hide + */ +export function hidden(str: string): string { + return run(str, code([8], 28)); +} + +/** + * Put horizontal line through the center of the text. + * @param str text to strike through + */ +export function strikethrough(str: string): string { + return run(str, code([9], 29)); +} + +/** + * Set text color to black. + * @param str text to make black + */ +export function black(str: string): string { + return run(str, code([30], 39)); +} + +/** + * Set text color to red. + * @param str text to make red + */ +export function red(str: string): string { + return run(str, code([31], 39)); +} + +/** + * Set text color to green. + * @param str text to make green + */ +export function green(str: string): string { + return run(str, code([32], 39)); +} + +/** + * Set text color to yellow. + * @param str text to make yellow + */ +export function yellow(str: string): string { + return run(str, code([33], 39)); +} + +/** + * Set text color to blue. + * @param str text to make blue + */ +export function blue(str: string): string { + return run(str, code([34], 39)); +} + +/** + * Set text color to magenta. + * @param str text to make magenta + */ +export function magenta(str: string): string { + return run(str, code([35], 39)); +} + +/** + * Set text color to cyan. + * @param str text to make cyan + */ +export function cyan(str: string): string { + return run(str, code([36], 39)); +} + +/** + * Set text color to white. + * @param str text to make white + */ +export function white(str: string): string { + return run(str, code([37], 39)); +} + +/** + * Set text color to gray. + * @param str text to make gray + */ +export function gray(str: string): string { + return brightBlack(str); +} + +/** + * Set text color to bright black. + * @param str text to make bright-black + */ +export function brightBlack(str: string): string { + return run(str, code([90], 39)); +} + +/** + * Set text color to bright red. + * @param str text to make bright-red + */ +export function brightRed(str: string): string { + return run(str, code([91], 39)); +} + +/** + * Set text color to bright green. + * @param str text to make bright-green + */ +export function brightGreen(str: string): string { + return run(str, code([92], 39)); +} + +/** + * Set text color to bright yellow. + * @param str text to make bright-yellow + */ +export function brightYellow(str: string): string { + return run(str, code([93], 39)); +} + +/** + * Set text color to bright blue. + * @param str text to make bright-blue + */ +export function brightBlue(str: string): string { + return run(str, code([94], 39)); +} + +/** + * Set text color to bright magenta. + * @param str text to make bright-magenta + */ +export function brightMagenta(str: string): string { + return run(str, code([95], 39)); +} + +/** + * Set text color to bright cyan. + * @param str text to make bright-cyan + */ +export function brightCyan(str: string): string { + return run(str, code([96], 39)); +} + +/** + * Set text color to bright white. + * @param str text to make bright-white + */ +export function brightWhite(str: string): string { + return run(str, code([97], 39)); +} + +/** + * Set background color to black. + * @param str text to make its background black + */ +export function bgBlack(str: string): string { + return run(str, code([40], 49)); +} + +/** + * Set background color to red. + * @param str text to make its background red + */ +export function bgRed(str: string): string { + return run(str, code([41], 49)); +} + +/** + * Set background color to green. + * @param str text to make its background green + */ +export function bgGreen(str: string): string { + return run(str, code([42], 49)); +} + +/** + * Set background color to yellow. + * @param str text to make its background yellow + */ +export function bgYellow(str: string): string { + return run(str, code([43], 49)); +} + +/** + * Set background color to blue. + * @param str text to make its background blue + */ +export function bgBlue(str: string): string { + return run(str, code([44], 49)); +} + +/** + * Set background color to magenta. + * @param str text to make its background magenta + */ +export function bgMagenta(str: string): string { + return run(str, code([45], 49)); +} + +/** + * Set background color to cyan. + * @param str text to make its background cyan + */ +export function bgCyan(str: string): string { + return run(str, code([46], 49)); +} + +/** + * Set background color to white. + * @param str text to make its background white + */ +export function bgWhite(str: string): string { + return run(str, code([47], 49)); +} + +/** + * Set background color to bright black. + * @param str text to make its background bright-black + */ +export function bgBrightBlack(str: string): string { + return run(str, code([100], 49)); +} + +/** + * Set background color to bright red. + * @param str text to make its background bright-red + */ +export function bgBrightRed(str: string): string { + return run(str, code([101], 49)); +} + +/** + * Set background color to bright green. + * @param str text to make its background bright-green + */ +export function bgBrightGreen(str: string): string { + return run(str, code([102], 49)); +} + +/** + * Set background color to bright yellow. + * @param str text to make its background bright-yellow + */ +export function bgBrightYellow(str: string): string { + return run(str, code([103], 49)); +} + +/** + * Set background color to bright blue. + * @param str text to make its background bright-blue + */ +export function bgBrightBlue(str: string): string { + return run(str, code([104], 49)); +} + +/** + * Set background color to bright magenta. + * @param str text to make its background bright-magenta + */ +export function bgBrightMagenta(str: string): string { + return run(str, code([105], 49)); +} + +/** + * Set background color to bright cyan. + * @param str text to make its background bright-cyan + */ +export function bgBrightCyan(str: string): string { + return run(str, code([106], 49)); +} + +/** + * Set background color to bright white. + * @param str text to make its background bright-white + */ +export function bgBrightWhite(str: string): string { + return run(str, code([107], 49)); +} + +/* Special Color Sequences */ + +/** + * Clam and truncate color codes + * @param n + * @param max number to truncate to + * @param min number to truncate from + */ +function clampAndTruncate(n: number, max = 255, min = 0): number { + return Math.trunc(Math.max(Math.min(n, max), min)); +} + +/** + * Set text color using paletted 8bit colors. + * https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit + * @param str text color to apply paletted 8bit colors to + * @param color code + */ +export function rgb8(str: string, color: number): string { + return run(str, code([38, 5, clampAndTruncate(color)], 39)); +} + +/** + * Set background color using paletted 8bit colors. + * https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit + * @param str text color to apply paletted 8bit background colors to + * @param color code + */ +export function bgRgb8(str: string, color: number): string { + return run(str, code([48, 5, clampAndTruncate(color)], 49)); +} + +/** + * Set text color using 24bit rgb. + * `color` can be a number in range `0x000000` to `0xffffff` or + * an `Rgb`. + * + * To produce the color magenta: + * + * ```ts + * import { rgb24 } from "https://deno.land/std@$STD_VERSION/fmt/colors.ts"; + * rgb24("foo", 0xff00ff); + * rgb24("foo", {r: 255, g: 0, b: 255}); + * ``` + * @param str text color to apply 24bit rgb to + * @param color code + */ +export function rgb24(str: string, color: number | Rgb): string { + if (typeof color === "number") { + return run( + str, + code( + [38, 2, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff], + 39, + ), + ); + } + return run( + str, + code( + [ + 38, + 2, + clampAndTruncate(color.r), + clampAndTruncate(color.g), + clampAndTruncate(color.b), + ], + 39, + ), + ); +} + +/** + * Set background color using 24bit rgb. + * `color` can be a number in range `0x000000` to `0xffffff` or + * an `Rgb`. + * + * To produce the color magenta: + * + * ```ts + * import { bgRgb24 } from "https://deno.land/std@$STD_VERSION/fmt/colors.ts"; + * bgRgb24("foo", 0xff00ff); + * bgRgb24("foo", {r: 255, g: 0, b: 255}); + * ``` + * @param str text color to apply 24bit rgb to + * @param color code + */ +export function bgRgb24(str: string, color: number | Rgb): string { + if (typeof color === "number") { + return run( + str, + code( + [48, 2, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff], + 49, + ), + ); + } + return run( + str, + code( + [ + 48, + 2, + clampAndTruncate(color.r), + clampAndTruncate(color.g), + clampAndTruncate(color.b), + ], + 49, + ), + ); +} + +// https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js +const ANSI_PATTERN = new RegExp( + [ + "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", + "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", + ].join("|"), + "g", +); + +/** + * Remove ANSI escape codes from the string. + * @param string to remove ANSI escape codes from + */ +export function stripColor(string: string): string { + return string.replace(ANSI_PATTERN, ""); +} diff --git a/vendor/deno.land/std@0.191.0/streams/_common.ts b/vendor/deno.land/std@0.191.0/streams/_common.ts new file mode 100644 index 0000000..7825ba0 --- /dev/null +++ b/vendor/deno.land/std@0.191.0/streams/_common.ts @@ -0,0 +1,26 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +export const DEFAULT_CHUNK_SIZE = 16_640; +export const DEFAULT_BUFFER_SIZE = 32 * 1024; + +/** Generate longest proper prefix which is also suffix array. */ +export function createLPS(pat: Uint8Array): Uint8Array { + const lps = new Uint8Array(pat.length); + lps[0] = 0; + let prefixEnd = 0; + let i = 1; + while (i < lps.length) { + if (pat[i] == pat[prefixEnd]) { + prefixEnd++; + lps[i] = prefixEnd; + i++; + } else if (prefixEnd === 0) { + lps[i] = 0; + i++; + } else { + prefixEnd = lps[prefixEnd - 1]; + } + } + return lps; +} diff --git a/vendor/deno.land/std@0.191.0/streams/iterate_reader.ts b/vendor/deno.land/std@0.191.0/streams/iterate_reader.ts new file mode 100644 index 0000000..8d3fe73 --- /dev/null +++ b/vendor/deno.land/std@0.191.0/streams/iterate_reader.ts @@ -0,0 +1,102 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { DEFAULT_BUFFER_SIZE } from "./_common.ts"; +import type { Reader, ReaderSync } from "../types.d.ts"; + +/** Turns a Reader, `r`, into an async iterator. + * + * ```ts + * import { iterateReader } from "https://deno.land/std@$STD_VERSION/streams/iterate_reader.ts"; + * + * let f = await Deno.open("/etc/passwd"); + * for await (const chunk of iterateReader(f)) { + * console.log(chunk); + * } + * f.close(); + * ``` + * + * Second argument can be used to tune size of a buffer. + * Default size of the buffer is 32kB. + * + * ```ts + * import { iterateReader } from "https://deno.land/std@$STD_VERSION/streams/iterate_reader.ts"; + * + * let f = await Deno.open("/etc/passwd"); + * const it = iterateReader(f, { + * bufSize: 1024 * 1024 + * }); + * for await (const chunk of it) { + * console.log(chunk); + * } + * f.close(); + * ``` + */ +export async function* iterateReader( + r: Reader, + options?: { + bufSize?: number; + }, +): AsyncIterableIterator { + const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE; + const b = new Uint8Array(bufSize); + while (true) { + const result = await r.read(b); + if (result === null) { + break; + } + + yield b.slice(0, result); + } +} + +/** Turns a ReaderSync, `r`, into an iterator. + * + * ```ts + * import { iterateReaderSync } from "https://deno.land/std@$STD_VERSION/streams/iterate_reader.ts"; + * + * let f = Deno.openSync("/etc/passwd"); + * for (const chunk of iterateReaderSync(f)) { + * console.log(chunk); + * } + * f.close(); + * ``` + * + * Second argument can be used to tune size of a buffer. + * Default size of the buffer is 32kB. + * + * ```ts + * import { iterateReaderSync } from "https://deno.land/std@$STD_VERSION/streams/iterate_reader.ts"; + + * let f = await Deno.open("/etc/passwd"); + * const iter = iterateReaderSync(f, { + * bufSize: 1024 * 1024 + * }); + * for (const chunk of iter) { + * console.log(chunk); + * } + * f.close(); + * ``` + * + * Iterator uses an internal buffer of fixed size for efficiency; it returns + * a view on that buffer on each iteration. It is therefore caller's + * responsibility to copy contents of the buffer if needed; otherwise the + * next iteration will overwrite contents of previously returned chunk. + */ +export function* iterateReaderSync( + r: ReaderSync, + options?: { + bufSize?: number; + }, +): IterableIterator { + const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE; + const b = new Uint8Array(bufSize); + while (true) { + const result = r.readSync(b); + if (result === null) { + break; + } + + yield b.slice(0, result); + } +} diff --git a/vendor/deno.land/std@0.191.0/testing/_diff.ts b/vendor/deno.land/std@0.191.0/testing/_diff.ts new file mode 100644 index 0000000..bd416e5 --- /dev/null +++ b/vendor/deno.land/std@0.191.0/testing/_diff.ts @@ -0,0 +1,440 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { + bgGreen, + bgRed, + bold, + gray, + green, + red, + white, +} from "../fmt/colors.ts"; + +interface FarthestPoint { + y: number; + id: number; +} + +export enum DiffType { + removed = "removed", + common = "common", + added = "added", +} + +export interface DiffResult { + type: DiffType; + value: T; + details?: Array>; +} + +const REMOVED = 1; +const COMMON = 2; +const ADDED = 3; + +function createCommon(A: T[], B: T[], reverse?: boolean): T[] { + const common = []; + if (A.length === 0 || B.length === 0) return []; + for (let i = 0; i < Math.min(A.length, B.length); i += 1) { + if ( + A[reverse ? A.length - i - 1 : i] === B[reverse ? B.length - i - 1 : i] + ) { + common.push(A[reverse ? A.length - i - 1 : i]); + } else { + return common; + } + } + return common; +} + +/** + * Renders the differences between the actual and expected values + * @param A Actual value + * @param B Expected value + */ +export function diff(A: T[], B: T[]): Array> { + const prefixCommon = createCommon(A, B); + const suffixCommon = createCommon( + A.slice(prefixCommon.length), + B.slice(prefixCommon.length), + true, + ).reverse(); + A = suffixCommon.length + ? A.slice(prefixCommon.length, -suffixCommon.length) + : A.slice(prefixCommon.length); + B = suffixCommon.length + ? B.slice(prefixCommon.length, -suffixCommon.length) + : B.slice(prefixCommon.length); + const swapped = B.length > A.length; + [A, B] = swapped ? [B, A] : [A, B]; + const M = A.length; + const N = B.length; + if (!M && !N && !suffixCommon.length && !prefixCommon.length) return []; + if (!N) { + return [ + ...prefixCommon.map( + (c): DiffResult => ({ type: DiffType.common, value: c }), + ), + ...A.map( + (a): DiffResult => ({ + type: swapped ? DiffType.added : DiffType.removed, + value: a, + }), + ), + ...suffixCommon.map( + (c): DiffResult => ({ type: DiffType.common, value: c }), + ), + ]; + } + const offset = N; + const delta = M - N; + const size = M + N + 1; + const fp: FarthestPoint[] = Array.from( + { length: size }, + () => ({ y: -1, id: -1 }), + ); + /** + * INFO: + * This buffer is used to save memory and improve performance. + * The first half is used to save route and last half is used to save diff + * type. + * This is because, when I kept new uint8array area to save type,performance + * worsened. + */ + const routes = new Uint32Array((M * N + size + 1) * 2); + const diffTypesPtrOffset = routes.length / 2; + let ptr = 0; + let p = -1; + + function backTrace( + A: T[], + B: T[], + current: FarthestPoint, + swapped: boolean, + ): Array<{ + type: DiffType; + value: T; + }> { + const M = A.length; + const N = B.length; + const result = []; + let a = M - 1; + let b = N - 1; + let j = routes[current.id]; + let type = routes[current.id + diffTypesPtrOffset]; + while (true) { + if (!j && !type) break; + const prev = j; + if (type === REMOVED) { + result.unshift({ + type: swapped ? DiffType.removed : DiffType.added, + value: B[b], + }); + b -= 1; + } else if (type === ADDED) { + result.unshift({ + type: swapped ? DiffType.added : DiffType.removed, + value: A[a], + }); + a -= 1; + } else { + result.unshift({ type: DiffType.common, value: A[a] }); + a -= 1; + b -= 1; + } + j = routes[prev]; + type = routes[prev + diffTypesPtrOffset]; + } + return result; + } + + function createFP( + slide: FarthestPoint, + down: FarthestPoint, + k: number, + M: number, + ): FarthestPoint { + if (slide && slide.y === -1 && down && down.y === -1) { + return { y: 0, id: 0 }; + } + if ( + (down && down.y === -1) || + k === M || + (slide && slide.y) > (down && down.y) + 1 + ) { + const prev = slide.id; + ptr++; + routes[ptr] = prev; + routes[ptr + diffTypesPtrOffset] = ADDED; + return { y: slide.y, id: ptr }; + } else { + const prev = down.id; + ptr++; + routes[ptr] = prev; + routes[ptr + diffTypesPtrOffset] = REMOVED; + return { y: down.y + 1, id: ptr }; + } + } + + function snake( + k: number, + slide: FarthestPoint, + down: FarthestPoint, + _offset: number, + A: T[], + B: T[], + ): FarthestPoint { + const M = A.length; + const N = B.length; + if (k < -N || M < k) return { y: -1, id: -1 }; + const fp = createFP(slide, down, k, M); + while (fp.y + k < M && fp.y < N && A[fp.y + k] === B[fp.y]) { + const prev = fp.id; + ptr++; + fp.id = ptr; + fp.y += 1; + routes[ptr] = prev; + routes[ptr + diffTypesPtrOffset] = COMMON; + } + return fp; + } + + while (fp[delta + offset].y < N) { + p = p + 1; + for (let k = -p; k < delta; ++k) { + fp[k + offset] = snake( + k, + fp[k - 1 + offset], + fp[k + 1 + offset], + offset, + A, + B, + ); + } + for (let k = delta + p; k > delta; --k) { + fp[k + offset] = snake( + k, + fp[k - 1 + offset], + fp[k + 1 + offset], + offset, + A, + B, + ); + } + fp[delta + offset] = snake( + delta, + fp[delta - 1 + offset], + fp[delta + 1 + offset], + offset, + A, + B, + ); + } + return [ + ...prefixCommon.map( + (c): DiffResult => ({ type: DiffType.common, value: c }), + ), + ...backTrace(A, B, fp[delta + offset], swapped), + ...suffixCommon.map( + (c): DiffResult => ({ type: DiffType.common, value: c }), + ), + ]; +} + +/** + * Renders the differences between the actual and expected strings + * Partially inspired from https://github.com/kpdecker/jsdiff + * @param A Actual string + * @param B Expected string + */ +export function diffstr(A: string, B: string) { + function unescape(string: string): string { + // unescape invisible characters. + // ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#escape_sequences + return string + .replaceAll("\b", "\\b") + .replaceAll("\f", "\\f") + .replaceAll("\t", "\\t") + .replaceAll("\v", "\\v") + .replaceAll( // does not remove line breaks + /\r\n|\r|\n/g, + (str) => str === "\r" ? "\\r" : str === "\n" ? "\\n\n" : "\\r\\n\r\n", + ); + } + + function tokenize(string: string, { wordDiff = false } = {}): string[] { + if (wordDiff) { + // Split string on whitespace symbols + const tokens = string.split(/([^\S\r\n]+|[()[\]{}'"\r\n]|\b)/); + // Extended Latin character set + const words = + /^[a-zA-Z\u{C0}-\u{FF}\u{D8}-\u{F6}\u{F8}-\u{2C6}\u{2C8}-\u{2D7}\u{2DE}-\u{2FF}\u{1E00}-\u{1EFF}]+$/u; + + // Join boundary splits that we do not consider to be boundaries and merge empty strings surrounded by word chars + for (let i = 0; i < tokens.length - 1; i++) { + if ( + !tokens[i + 1] && tokens[i + 2] && words.test(tokens[i]) && + words.test(tokens[i + 2]) + ) { + tokens[i] += tokens[i + 2]; + tokens.splice(i + 1, 2); + i--; + } + } + return tokens.filter((token) => token); + } else { + // Split string on new lines symbols + const tokens = [], lines = string.split(/(\n|\r\n)/); + + // Ignore final empty token when text ends with a newline + if (!lines[lines.length - 1]) { + lines.pop(); + } + + // Merge the content and line separators into single tokens + for (let i = 0; i < lines.length; i++) { + if (i % 2) { + tokens[tokens.length - 1] += lines[i]; + } else { + tokens.push(lines[i]); + } + } + return tokens; + } + } + + // Create details by filtering relevant word-diff for current line + // and merge "space-diff" if surrounded by word-diff for cleaner displays + function createDetails( + line: DiffResult, + tokens: Array>, + ) { + return tokens.filter(({ type }) => + type === line.type || type === DiffType.common + ).map((result, i, t) => { + if ( + (result.type === DiffType.common) && (t[i - 1]) && + (t[i - 1]?.type === t[i + 1]?.type) && /\s+/.test(result.value) + ) { + return { + ...result, + type: t[i - 1].type, + }; + } + return result; + }); + } + + // Compute multi-line diff + const diffResult = diff( + tokenize(`${unescape(A)}\n`), + tokenize(`${unescape(B)}\n`), + ); + + const added = [], removed = []; + for (const result of diffResult) { + if (result.type === DiffType.added) { + added.push(result); + } + if (result.type === DiffType.removed) { + removed.push(result); + } + } + + // Compute word-diff + const aLines = added.length < removed.length ? added : removed; + const bLines = aLines === removed ? added : removed; + for (const a of aLines) { + let tokens = [] as Array>, + b: undefined | DiffResult; + // Search another diff line with at least one common token + while (bLines.length) { + b = bLines.shift(); + tokens = diff( + tokenize(a.value, { wordDiff: true }), + tokenize(b?.value ?? "", { wordDiff: true }), + ); + if ( + tokens.some(({ type, value }) => + type === DiffType.common && value.trim().length + ) + ) { + break; + } + } + // Register word-diff details + a.details = createDetails(a, tokens); + if (b) { + b.details = createDetails(b, tokens); + } + } + + return diffResult; +} + +/** + * Colors the output of assertion diffs + * @param diffType Difference type, either added or removed + */ +function createColor( + diffType: DiffType, + { background = false } = {}, +): (s: string) => string { + // TODO(@littledivy): Remove this when we can detect + // true color terminals. + // https://github.com/denoland/deno_std/issues/2575 + background = false; + switch (diffType) { + case DiffType.added: + return (s: string): string => + background ? bgGreen(white(s)) : green(bold(s)); + case DiffType.removed: + return (s: string): string => background ? bgRed(white(s)) : red(bold(s)); + default: + return white; + } +} + +/** + * Prefixes `+` or `-` in diff output + * @param diffType Difference type, either added or removed + */ +function createSign(diffType: DiffType): string { + switch (diffType) { + case DiffType.added: + return "+ "; + case DiffType.removed: + return "- "; + default: + return " "; + } +} + +export function buildMessage( + diffResult: ReadonlyArray>, + { stringDiff = false } = {}, +): string[] { + const messages: string[] = [], diffMessages: string[] = []; + messages.push(""); + messages.push(""); + messages.push( + ` ${gray(bold("[Diff]"))} ${red(bold("Actual"))} / ${ + green(bold("Expected")) + }`, + ); + messages.push(""); + messages.push(""); + diffResult.forEach((result: DiffResult) => { + const c = createColor(result.type); + const line = result.details?.map((detail) => + detail.type !== DiffType.common + ? createColor(detail.type, { background: true })(detail.value) + : detail.value + ).join("") ?? result.value; + diffMessages.push(c(`${createSign(result.type)}${line}`)); + }); + messages.push(...(stringDiff ? [diffMessages.join("")] : diffMessages)); + messages.push(""); + + return messages; +} diff --git a/vendor/deno.land/std@0.191.0/testing/_format.ts b/vendor/deno.land/std@0.191.0/testing/_format.ts new file mode 100644 index 0000000..4496aa6 --- /dev/null +++ b/vendor/deno.land/std@0.191.0/testing/_format.ts @@ -0,0 +1,23 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +/** + * Converts the input into a string. Objects, Sets and Maps are sorted so as to + * make tests less flaky + * @param v Value to be formatted + */ +export function format(v: unknown): string { + // deno-lint-ignore no-explicit-any + const { Deno } = globalThis as any; + return typeof Deno?.inspect === "function" + ? Deno.inspect(v, { + depth: Infinity, + sorted: true, + trailingComma: true, + compact: false, + iterableLimit: Infinity, + // getters should be true in assertEquals. + getters: true, + }) + : `"${String(v).replace(/(?=["\\])/g, "\\")}"`; +} diff --git a/vendor/deno.land/std@0.191.0/testing/asserts.ts b/vendor/deno.land/std@0.191.0/testing/asserts.ts new file mode 100644 index 0000000..654ea03 --- /dev/null +++ b/vendor/deno.land/std@0.191.0/testing/asserts.ts @@ -0,0 +1,917 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +/** A library of assertion functions. + * If the assertion is false an `AssertionError` will be thrown which will + * result in pretty-printed diff of failing assertion. + * + * This module is browser compatible, but do not rely on good formatting of + * values for AssertionError messages in browsers. + * + * @module + */ + +import { red, stripColor } from "../fmt/colors.ts"; +import { buildMessage, diff, diffstr } from "./_diff.ts"; +import { format } from "./_format.ts"; + +const CAN_NOT_DISPLAY = "[Cannot display]"; + +export class AssertionError extends Error { + override name = "AssertionError"; + constructor(message: string) { + super(message); + } +} + +function isKeyedCollection(x: unknown): x is Set { + return [Symbol.iterator, "size"].every((k) => k in (x as Set)); +} + +/** + * Deep equality comparison used in assertions + * @param c actual value + * @param d expected value + */ +export function equal(c: unknown, d: unknown): boolean { + const seen = new Map(); + return (function compare(a: unknown, b: unknown): boolean { + // Have to render RegExp & Date for string comparison + // unless it's mistreated as object + if ( + a && + b && + ((a instanceof RegExp && b instanceof RegExp) || + (a instanceof URL && b instanceof URL)) + ) { + return String(a) === String(b); + } + if (a instanceof Date && b instanceof Date) { + const aTime = a.getTime(); + const bTime = b.getTime(); + // Check for NaN equality manually since NaN is not + // equal to itself. + if (Number.isNaN(aTime) && Number.isNaN(bTime)) { + return true; + } + return aTime === bTime; + } + if (typeof a === "number" && typeof b === "number") { + return Number.isNaN(a) && Number.isNaN(b) || a === b; + } + if (Object.is(a, b)) { + return true; + } + if (a && typeof a === "object" && b && typeof b === "object") { + if (a && b && !constructorsEqual(a, b)) { + return false; + } + if (a instanceof WeakMap || b instanceof WeakMap) { + if (!(a instanceof WeakMap && b instanceof WeakMap)) return false; + throw new TypeError("cannot compare WeakMap instances"); + } + if (a instanceof WeakSet || b instanceof WeakSet) { + if (!(a instanceof WeakSet && b instanceof WeakSet)) return false; + throw new TypeError("cannot compare WeakSet instances"); + } + if (seen.get(a) === b) { + return true; + } + if (Object.keys(a || {}).length !== Object.keys(b || {}).length) { + return false; + } + seen.set(a, b); + if (isKeyedCollection(a) && isKeyedCollection(b)) { + if (a.size !== b.size) { + return false; + } + + let unmatchedEntries = a.size; + + for (const [aKey, aValue] of a.entries()) { + for (const [bKey, bValue] of b.entries()) { + /* Given that Map keys can be references, we need + * to ensure that they are also deeply equal */ + if ( + (aKey === aValue && bKey === bValue && compare(aKey, bKey)) || + (compare(aKey, bKey) && compare(aValue, bValue)) + ) { + unmatchedEntries--; + break; + } + } + } + + return unmatchedEntries === 0; + } + const merged = { ...a, ...b }; + for ( + const key of [ + ...Object.getOwnPropertyNames(merged), + ...Object.getOwnPropertySymbols(merged), + ] + ) { + type Key = keyof typeof merged; + if (!compare(a && a[key as Key], b && b[key as Key])) { + return false; + } + if (((key in a) && (!(key in b))) || ((key in b) && (!(key in a)))) { + return false; + } + } + if (a instanceof WeakRef || b instanceof WeakRef) { + if (!(a instanceof WeakRef && b instanceof WeakRef)) return false; + return compare(a.deref(), b.deref()); + } + return true; + } + return false; + })(c, d); +} + +// deno-lint-ignore ban-types +function constructorsEqual(a: object, b: object) { + return a.constructor === b.constructor || + a.constructor === Object && !b.constructor || + !a.constructor && b.constructor === Object; +} + +/** Make an assertion, error will be thrown if `expr` does not have truthy value. */ +export function assert(expr: unknown, msg = ""): asserts expr { + if (!expr) { + throw new AssertionError(msg); + } +} + +/** Make an assertion, error will be thrown if `expr` have truthy value. */ +type Falsy = false | 0 | 0n | "" | null | undefined; +export function assertFalse(expr: unknown, msg = ""): asserts expr is Falsy { + if (expr) { + throw new AssertionError(msg); + } +} + +/** + * Make an assertion that `actual` and `expected` are equal, deeply. If not + * deeply equal, then throw. + * + * Type parameter can be specified to ensure values under comparison have the same type. + * + * @example + * ```ts + * import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * Deno.test("example", function (): void { + * assertEquals("world", "world"); + * assertEquals({ hello: "world" }, { hello: "world" }); + * }); + * ``` + */ +export function assertEquals(actual: T, expected: T, msg?: string) { + if (equal(actual, expected)) { + return; + } + const msgSuffix = msg ? `: ${msg}` : "."; + let message = `Values are not equal${msgSuffix}`; + + const actualString = format(actual); + const expectedString = format(expected); + try { + const stringDiff = (typeof actual === "string") && + (typeof expected === "string"); + const diffResult = stringDiff + ? diffstr(actual as string, expected as string) + : diff(actualString.split("\n"), expectedString.split("\n")); + const diffMsg = buildMessage(diffResult, { stringDiff }).join("\n"); + message = `${message}\n${diffMsg}`; + } catch { + message = `${message}\n${red(CAN_NOT_DISPLAY)} + \n\n`; + } + throw new AssertionError(message); +} + +/** + * Make an assertion that `actual` and `expected` are not equal, deeply. + * If not then throw. + * + * Type parameter can be specified to ensure values under comparison have the same type. + * + * @example + * ```ts + * import { assertNotEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * assertNotEquals(1, 2) + * ``` + */ +export function assertNotEquals(actual: T, expected: T, msg?: string) { + if (!equal(actual, expected)) { + return; + } + let actualString: string; + let expectedString: string; + try { + actualString = String(actual); + } catch { + actualString = "[Cannot display]"; + } + try { + expectedString = String(expected); + } catch { + expectedString = "[Cannot display]"; + } + const msgSuffix = msg ? `: ${msg}` : "."; + throw new AssertionError( + `Expected actual: ${actualString} not to be: ${expectedString}${msgSuffix}`, + ); +} + +/** + * Make an assertion that `actual` and `expected` are strictly equal. If + * not then throw. + * + * @example + * ```ts + * import { assertStrictEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * Deno.test("isStrictlyEqual", function (): void { + * const a = {}; + * const b = a; + * assertStrictEquals(a, b); + * }); + * + * // This test fails + * Deno.test("isNotStrictlyEqual", function (): void { + * const a = {}; + * const b = {}; + * assertStrictEquals(a, b); + * }); + * ``` + */ +export function assertStrictEquals( + actual: unknown, + expected: T, + msg?: string, +): asserts actual is T { + if (Object.is(actual, expected)) { + return; + } + + const msgSuffix = msg ? `: ${msg}` : "."; + let message: string; + + const actualString = format(actual); + const expectedString = format(expected); + + if (actualString === expectedString) { + const withOffset = actualString + .split("\n") + .map((l) => ` ${l}`) + .join("\n"); + message = + `Values have the same structure but are not reference-equal${msgSuffix}\n\n${ + red(withOffset) + }\n`; + } else { + try { + const stringDiff = (typeof actual === "string") && + (typeof expected === "string"); + const diffResult = stringDiff + ? diffstr(actual as string, expected as string) + : diff(actualString.split("\n"), expectedString.split("\n")); + const diffMsg = buildMessage(diffResult, { stringDiff }).join("\n"); + message = `Values are not strictly equal${msgSuffix}\n${diffMsg}`; + } catch { + message = `\n${red(CAN_NOT_DISPLAY)} + \n\n`; + } + } + + throw new AssertionError(message); +} + +/** + * Make an assertion that `actual` and `expected` are not strictly equal. + * If the values are strictly equal then throw. + * + * ```ts + * import { assertNotStrictEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * assertNotStrictEquals(1, 1) + * ``` + */ +export function assertNotStrictEquals( + actual: T, + expected: T, + msg?: string, +) { + if (!Object.is(actual, expected)) { + return; + } + + const msgSuffix = msg ? `: ${msg}` : "."; + throw new AssertionError( + `Expected "actual" to be strictly unequal to: ${ + format(actual) + }${msgSuffix}\n`, + ); +} + +/** + * Make an assertion that `actual` and `expected` are almost equal numbers through + * a given tolerance. It can be used to take into account IEEE-754 double-precision + * floating-point representation limitations. + * If the values are not almost equal then throw. + * + * @example + * ```ts + * import { assertAlmostEquals, assertThrows } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * assertAlmostEquals(0.1, 0.2); + * + * // Using a custom tolerance value + * assertAlmostEquals(0.1 + 0.2, 0.3, 1e-16); + * assertThrows(() => assertAlmostEquals(0.1 + 0.2, 0.3, 1e-17)); + * ``` + */ +export function assertAlmostEquals( + actual: number, + expected: number, + tolerance = 1e-7, + msg?: string, +) { + if (Object.is(actual, expected)) { + return; + } + const delta = Math.abs(expected - actual); + if (delta <= tolerance) { + return; + } + + const msgSuffix = msg ? `: ${msg}` : "."; + const f = (n: number) => Number.isInteger(n) ? n : n.toExponential(); + throw new AssertionError( + `Expected actual: "${f(actual)}" to be close to "${f(expected)}": \ +delta "${f(delta)}" is greater than "${f(tolerance)}"${msgSuffix}`, + ); +} + +// deno-lint-ignore no-explicit-any +type AnyConstructor = new (...args: any[]) => any; +type GetConstructorType = T extends // deno-lint-ignore no-explicit-any +new (...args: any) => infer C ? C + : never; + +/** + * Make an assertion that `obj` is an instance of `type`. + * If not then throw. + */ +export function assertInstanceOf( + actual: unknown, + expectedType: T, + msg = "", +): asserts actual is GetConstructorType { + if (actual instanceof expectedType) return; + + const msgSuffix = msg ? `: ${msg}` : "."; + const expectedTypeStr = expectedType.name; + + let actualTypeStr = ""; + if (actual === null) { + actualTypeStr = "null"; + } else if (actual === undefined) { + actualTypeStr = "undefined"; + } else if (typeof actual === "object") { + actualTypeStr = actual.constructor?.name ?? "Object"; + } else { + actualTypeStr = typeof actual; + } + + if (expectedTypeStr == actualTypeStr) { + msg = + `Expected object to be an instance of "${expectedTypeStr}"${msgSuffix}`; + } else if (actualTypeStr == "function") { + msg = + `Expected object to be an instance of "${expectedTypeStr}" but was not an instanced object${msgSuffix}`; + } else { + msg = + `Expected object to be an instance of "${expectedTypeStr}" but was "${actualTypeStr}"${msgSuffix}`; + } + + throw new AssertionError(msg); +} + +/** + * Make an assertion that `obj` is not an instance of `type`. + * If so, then throw. + */ +export function assertNotInstanceOf( + actual: A, + // deno-lint-ignore no-explicit-any + unexpectedType: new (...args: any[]) => T, + msg?: string, +): asserts actual is Exclude { + const msgSuffix = msg ? `: ${msg}` : "."; + msg = + `Expected object to not be an instance of "${typeof unexpectedType}"${msgSuffix}`; + assertFalse(actual instanceof unexpectedType, msg); +} + +/** + * Make an assertion that actual is not null or undefined. + * If not then throw. + */ +export function assertExists( + actual: T, + msg?: string, +): asserts actual is NonNullable { + if (actual === undefined || actual === null) { + const msgSuffix = msg ? `: ${msg}` : "."; + msg = + `Expected actual: "${actual}" to not be null or undefined${msgSuffix}`; + throw new AssertionError(msg); + } +} + +/** + * Make an assertion that actual includes expected. If not + * then throw. + */ +export function assertStringIncludes( + actual: string, + expected: string, + msg?: string, +) { + if (!actual.includes(expected)) { + const msgSuffix = msg ? `: ${msg}` : "."; + msg = `Expected actual: "${actual}" to contain: "${expected}"${msgSuffix}`; + throw new AssertionError(msg); + } +} + +/** + * Make an assertion that `actual` includes the `expected` values. + * If not then an error will be thrown. + * + * Type parameter can be specified to ensure values under comparison have the same type. + * + * @example + * ```ts + * import { assertArrayIncludes } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * assertArrayIncludes([1, 2], [2]) + * ``` + */ +export function assertArrayIncludes( + actual: ArrayLike, + expected: ArrayLike, + msg?: string, +) { + const missing: unknown[] = []; + for (let i = 0; i < expected.length; i++) { + let found = false; + for (let j = 0; j < actual.length; j++) { + if (equal(expected[i], actual[j])) { + found = true; + break; + } + } + if (!found) { + missing.push(expected[i]); + } + } + if (missing.length === 0) { + return; + } + + const msgSuffix = msg ? `: ${msg}` : "."; + msg = `Expected actual: "${format(actual)}" to include: "${ + format(expected) + }"${msgSuffix}\nmissing: ${format(missing)}`; + throw new AssertionError(msg); +} + +/** + * Make an assertion that `actual` match RegExp `expected`. If not + * then throw. + */ +export function assertMatch( + actual: string, + expected: RegExp, + msg?: string, +) { + if (!expected.test(actual)) { + const msgSuffix = msg ? `: ${msg}` : "."; + msg = `Expected actual: "${actual}" to match: "${expected}"${msgSuffix}`; + throw new AssertionError(msg); + } +} + +/** + * Make an assertion that `actual` not match RegExp `expected`. If match + * then throw. + */ +export function assertNotMatch( + actual: string, + expected: RegExp, + msg?: string, +) { + if (expected.test(actual)) { + const msgSuffix = msg ? `: ${msg}` : "."; + msg = + `Expected actual: "${actual}" to not match: "${expected}"${msgSuffix}`; + throw new AssertionError(msg); + } +} + +/** + * Make an assertion that `actual` object is a subset of `expected` object, deeply. + * If not, then throw. + */ +export function assertObjectMatch( + // deno-lint-ignore no-explicit-any + actual: Record, + expected: Record, + msg?: string, +) { + type loose = Record; + + function filter(a: loose, b: loose) { + const seen = new WeakMap(); + return fn(a, b); + + function fn(a: loose, b: loose): loose { + // Prevent infinite loop with circular references with same filter + if ((seen.has(a)) && (seen.get(a) === b)) { + return a; + } + seen.set(a, b); + // Filter keys and symbols which are present in both actual and expected + const filtered = {} as loose; + const entries = [ + ...Object.getOwnPropertyNames(a), + ...Object.getOwnPropertySymbols(a), + ] + .filter((key) => key in b) + .map((key) => [key, a[key as string]]) as Array<[string, unknown]>; + for (const [key, value] of entries) { + // On array references, build a filtered array and filter nested objects inside + if (Array.isArray(value)) { + const subset = (b as loose)[key]; + if (Array.isArray(subset)) { + filtered[key] = fn({ ...value }, { ...subset }); + continue; + } + } // On regexp references, keep value as it to avoid loosing pattern and flags + else if (value instanceof RegExp) { + filtered[key] = value; + continue; + } // On nested objects references, build a filtered object recursively + else if (typeof value === "object") { + const subset = (b as loose)[key]; + if ((typeof subset === "object") && (subset)) { + // When both operands are maps, build a filtered map with common keys and filter nested objects inside + if ((value instanceof Map) && (subset instanceof Map)) { + filtered[key] = new Map( + [...value].filter(([k]) => subset.has(k)).map(( + [k, v], + ) => [k, typeof v === "object" ? fn(v, subset.get(k)) : v]), + ); + continue; + } + // When both operands are set, build a filtered set with common values + if ((value instanceof Set) && (subset instanceof Set)) { + filtered[key] = new Set([...value].filter((v) => subset.has(v))); + continue; + } + filtered[key] = fn(value as loose, subset as loose); + continue; + } + } + filtered[key] = value; + } + return filtered; + } + } + return assertEquals( + // get the intersection of "actual" and "expected" + // side effect: all the instances' constructor field is "Object" now. + filter(actual, expected), + // set (nested) instances' constructor field to be "Object" without changing expected value. + // see https://github.com/denoland/deno_std/pull/1419 + filter(expected, expected), + msg, + ); +} + +/** + * Forcefully throws a failed assertion + */ +export function fail(msg?: string): never { + const msgSuffix = msg ? `: ${msg}` : "."; + assert(false, `Failed assertion${msgSuffix}`); +} + +/** + * Make an assertion that `error` is an `Error`. + * If not then an error will be thrown. + * An error class and a string that should be included in the + * error message can also be asserted. + */ +export function assertIsError( + error: unknown, + // deno-lint-ignore no-explicit-any + ErrorClass?: new (...args: any[]) => E, + msgIncludes?: string, + msg?: string, +): asserts error is E { + const msgSuffix = msg ? `: ${msg}` : "."; + if (error instanceof Error === false) { + throw new AssertionError( + `Expected "error" to be an Error object${msgSuffix}}`, + ); + } + if (ErrorClass && !(error instanceof ErrorClass)) { + msg = `Expected error to be instance of "${ErrorClass.name}", but was "${ + typeof error === "object" ? error?.constructor?.name : "[not an object]" + }"${msgSuffix}`; + throw new AssertionError(msg); + } + if ( + msgIncludes && (!(error instanceof Error) || + !stripColor(error.message).includes(stripColor(msgIncludes))) + ) { + msg = `Expected error message to include "${msgIncludes}", but got "${ + error instanceof Error ? error.message : "[not an Error]" + }"${msgSuffix}`; + throw new AssertionError(msg); + } +} + +/** + * Executes a function, expecting it to throw. If it does not, then it + * throws. + * + * @example + * ```ts + * import { assertThrows } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * Deno.test("doesThrow", function (): void { + * assertThrows((): void => { + * throw new TypeError("hello world!"); + * }); + * }); + * + * // This test will not pass. + * Deno.test("fails", function (): void { + * assertThrows((): void => { + * console.log("Hello world"); + * }); + * }); + * ``` + */ +export function assertThrows( + fn: () => unknown, + msg?: string, +): unknown; +/** + * Executes a function, expecting it to throw. If it does not, then it + * throws. An error class and a string that should be included in the + * error message can also be asserted. + * + * @example + * + * ```ts + * import { assertThrows } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * Deno.test("doesThrow", function (): void { + * assertThrows((): void => { + * throw new TypeError("hello world!"); + * }, TypeError); + * assertThrows( + * (): void => { + * throw new TypeError("hello world!"); + * }, + * TypeError, + * "hello", + * ); + * }); + * + * // This test will not pass. + * Deno.test("fails", function (): void { + * assertThrows((): void => { + * console.log("Hello world"); + * }); + * }); + * ``` + */ +export function assertThrows( + fn: () => unknown, + // deno-lint-ignore no-explicit-any + ErrorClass: new (...args: any[]) => E, + msgIncludes?: string, + msg?: string, +): E; +export function assertThrows( + fn: () => unknown, + errorClassOrMsg?: + // deno-lint-ignore no-explicit-any + | (new (...args: any[]) => E) + | string, + msgIncludesOrMsg?: string, + msg?: string, +): E | Error | unknown { + // deno-lint-ignore no-explicit-any + let ErrorClass: (new (...args: any[]) => E) | undefined = undefined; + let msgIncludes: string | undefined = undefined; + let err; + + if (typeof errorClassOrMsg !== "string") { + if ( + errorClassOrMsg === undefined || + errorClassOrMsg.prototype instanceof Error || + errorClassOrMsg.prototype === Error.prototype + ) { + // deno-lint-ignore no-explicit-any + ErrorClass = errorClassOrMsg as new (...args: any[]) => E; + msgIncludes = msgIncludesOrMsg; + } else { + msg = msgIncludesOrMsg; + } + } else { + msg = errorClassOrMsg; + } + let doesThrow = false; + const msgSuffix = msg ? `: ${msg}` : "."; + try { + fn(); + } catch (error) { + if (ErrorClass) { + if (error instanceof Error === false) { + throw new AssertionError(`A non-Error object was thrown${msgSuffix}`); + } + assertIsError( + error, + ErrorClass, + msgIncludes, + msg, + ); + } + err = error; + doesThrow = true; + } + if (!doesThrow) { + msg = `Expected function to throw${msgSuffix}`; + throw new AssertionError(msg); + } + return err; +} + +/** + * Executes a function which returns a promise, expecting it to reject. + * + * @example + * ```ts + * import { assertRejects } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * Deno.test("doesThrow", async function () { + * await assertRejects( + * async () => { + * throw new TypeError("hello world!"); + * }, + * ); + * await assertRejects( + * async () => { + * return Promise.reject(new Error()); + * }, + * ); + * }); + * + * // This test will not pass. + * Deno.test("fails", async function () { + * await assertRejects( + * async () => { + * console.log("Hello world"); + * }, + * ); + * }); + * ``` + */ +export function assertRejects( + fn: () => PromiseLike, + msg?: string, +): Promise; +/** + * Executes a function which returns a promise, expecting it to reject. + * If it does not, then it throws. An error class and a string that should be + * included in the error message can also be asserted. + * + * @example + * ```ts + * import { assertRejects } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts"; + * + * Deno.test("doesThrow", async function () { + * await assertRejects(async () => { + * throw new TypeError("hello world!"); + * }, TypeError); + * await assertRejects( + * async () => { + * throw new TypeError("hello world!"); + * }, + * TypeError, + * "hello", + * ); + * }); + * + * // This test will not pass. + * Deno.test("fails", async function () { + * await assertRejects( + * async () => { + * console.log("Hello world"); + * }, + * ); + * }); + * ``` + */ +export function assertRejects( + fn: () => PromiseLike, + // deno-lint-ignore no-explicit-any + ErrorClass: new (...args: any[]) => E, + msgIncludes?: string, + msg?: string, +): Promise; +export async function assertRejects( + fn: () => PromiseLike, + errorClassOrMsg?: + // deno-lint-ignore no-explicit-any + | (new (...args: any[]) => E) + | string, + msgIncludesOrMsg?: string, + msg?: string, +): Promise { + // deno-lint-ignore no-explicit-any + let ErrorClass: (new (...args: any[]) => E) | undefined = undefined; + let msgIncludes: string | undefined = undefined; + let err; + + if (typeof errorClassOrMsg !== "string") { + if ( + errorClassOrMsg === undefined || + errorClassOrMsg.prototype instanceof Error || + errorClassOrMsg.prototype === Error.prototype + ) { + // deno-lint-ignore no-explicit-any + ErrorClass = errorClassOrMsg as new (...args: any[]) => E; + msgIncludes = msgIncludesOrMsg; + } + } else { + msg = errorClassOrMsg; + } + let doesThrow = false; + let isPromiseReturned = false; + const msgSuffix = msg ? `: ${msg}` : "."; + try { + const possiblePromise = fn(); + if ( + possiblePromise && + typeof possiblePromise === "object" && + typeof possiblePromise.then === "function" + ) { + isPromiseReturned = true; + await possiblePromise; + } + } catch (error) { + if (!isPromiseReturned) { + throw new AssertionError( + `Function throws when expected to reject${msgSuffix}`, + ); + } + if (ErrorClass) { + if (error instanceof Error === false) { + throw new AssertionError(`A non-Error object was rejected${msgSuffix}`); + } + assertIsError( + error, + ErrorClass, + msgIncludes, + msg, + ); + } + err = error; + doesThrow = true; + } + if (!doesThrow) { + throw new AssertionError( + `Expected function to reject${msgSuffix}`, + ); + } + return err; +} + +/** Use this to stub out methods that will throw when invoked. */ +export function unimplemented(msg?: string): never { + const msgSuffix = msg ? `: ${msg}` : "."; + throw new AssertionError(`Unimplemented${msgSuffix}`); +} + +/** Use this to assert unreachable code. */ +export function unreachable(): never { + throw new AssertionError("unreachable"); +} diff --git a/vendor/deno.land/std@0.191.0/types.d.ts b/vendor/deno.land/std@0.191.0/types.d.ts new file mode 100644 index 0000000..f3769a8 --- /dev/null +++ b/vendor/deno.land/std@0.191.0/types.d.ts @@ -0,0 +1,90 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +/** See the Contributing > Types section in the README for an explanation of this file. */ + +/** An abstract interface which when implemented provides an interface to read bytes into an array buffer asynchronously. */ +export interface Reader { + /** Reads up to `p.byteLength` bytes into `p`. It resolves to the number of + * bytes read (`0` < `n` <= `p.byteLength`) and rejects if any error + * encountered. Even if `read()` resolves to `n` < `p.byteLength`, it may + * use all of `p` as scratch space during the call. If some data is + * available but not `p.byteLength` bytes, `read()` conventionally resolves + * to what is available instead of waiting for more. + * + * When `read()` encounters end-of-file condition, it resolves to EOF + * (`null`). + * + * When `read()` encounters an error, it rejects with an error. + * + * Callers should always process the `n` > `0` bytes returned before + * considering the EOF (`null`). Doing so correctly handles I/O errors that + * happen after reading some bytes and also both of the allowed EOF + * behaviors. + * + * Implementations should not retain a reference to `p`. + * + * Use iterateReader() from https://deno.land/std@$STD_VERSION/streams/iterate_reader.ts to turn a Reader into an + * AsyncIterator. + */ + read(p: Uint8Array): Promise; +} + +/** An abstract interface which when implemented provides an interface to read bytes into an array buffer synchronously. */ +export interface ReaderSync { + /** Reads up to `p.byteLength` bytes into `p`. It resolves to the number + * of bytes read (`0` < `n` <= `p.byteLength`) and rejects if any error + * encountered. Even if `read()` returns `n` < `p.byteLength`, it may use + * all of `p` as scratch space during the call. If some data is available + * but not `p.byteLength` bytes, `read()` conventionally returns what is + * available instead of waiting for more. + * + * When `readSync()` encounters end-of-file condition, it returns EOF + * (`null`). + * + * When `readSync()` encounters an error, it throws with an error. + * + * Callers should always process the `n` > `0` bytes returned before + * considering the EOF (`null`). Doing so correctly handles I/O errors that happen + * after reading some bytes and also both of the allowed EOF behaviors. + * + * Implementations should not retain a reference to `p`. + * + * Use iterateReaderSync() from https://deno.land/std@$STD_VERSION/streams/iterate_reader.ts to turn a ReaderSync + * into an Iterator. + */ + readSync(p: Uint8Array): number | null; +} + +/** An abstract interface which when implemented provides an interface to write bytes from an array buffer to a file/resource asynchronously. */ +export interface Writer { + /** Writes `p.byteLength` bytes from `p` to the underlying data stream. It + * resolves to the number of bytes written from `p` (`0` <= `n` <= + * `p.byteLength`) or reject with the error encountered that caused the + * write to stop early. `write()` must reject with a non-null error if + * would resolve to `n` < `p.byteLength`. `write()` must not modify the + * slice data, even temporarily. + * + * Implementations should not retain a reference to `p`. + */ + write(p: Uint8Array): Promise; +} +/** An abstract interface which when implemented provides an interface to write bytes from an array buffer to a file/resource synchronously. */ +export interface WriterSync { + /** Writes `p.byteLength` bytes from `p` to the underlying data + * stream. It returns the number of bytes written from `p` (`0` <= `n` + * <= `p.byteLength`) and any error encountered that caused the write to + * stop early. `writeSync()` must throw a non-null error if it returns `n` < + * `p.byteLength`. `writeSync()` must not modify the slice data, even + * temporarily. + * + * Implementations should not retain a reference to `p`. + */ + writeSync(p: Uint8Array): number; +} + +/** An abstract interface which when implemented provides an interface to close files/resources that were previously opened. */ +export interface Closer { + /** Closes the resource, "freeing" the backing file/resource. */ + close(): void; +} diff --git a/vendor/deno.land/x/base64@v0.2.1/base.ts b/vendor/deno.land/x/base64@v0.2.1/base.ts new file mode 100644 index 0000000..1874151 --- /dev/null +++ b/vendor/deno.land/x/base64@v0.2.1/base.ts @@ -0,0 +1,136 @@ +function getLengths(b64: string): [number, number] { + const len: number = b64.length; + + // if (len % 4 > 0) { + // throw new TypeError("Invalid string. Length must be a multiple of 4"); + // } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + let validLen: number = b64.indexOf("="); + + if (validLen === -1) { + validLen = len; + } + + const placeHoldersLen: number = validLen === len ? 0 : 4 - (validLen % 4); + + return [validLen, placeHoldersLen]; +} + +export function init( + lookup: string[], + revLookup: number[], + urlsafe: boolean = false, +) { + function _byteLength(validLen: number, placeHoldersLen: number): number { + return Math.floor(((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen); + } + + function tripletToBase64(num: number): string { + return ( + lookup[(num >> 18) & 0x3f] + + lookup[(num >> 12) & 0x3f] + + lookup[(num >> 6) & 0x3f] + + lookup[num & 0x3f] + ); + } + + function encodeChunk(buf: Uint8Array, start: number, end: number): string { + const out: string[] = new Array((end - start) / 3); + + for (let i: number = start, curTriplet: number = 0; i < end; i += 3) { + out[curTriplet++] = tripletToBase64( + (buf[i] << 16) + (buf[i + 1] << 8) + buf[i + 2], + ); + } + + return out.join(""); + } + + return { + // base64 is 4/3 + up to two characters of the original data + byteLength(b64: string): number { + return _byteLength.apply(null, getLengths(b64)); + }, + toUint8Array(b64: string): Uint8Array { + const [validLen, placeHoldersLen]: number[] = getLengths(b64); + + const buf = new Uint8Array(_byteLength(validLen, placeHoldersLen)); + + // If there are placeholders, only get up to the last complete 4 chars + const len: number = placeHoldersLen ? validLen - 4 : validLen; + + let tmp: number; + let curByte: number = 0; + let i: number; + + for (i = 0; i < len; i += 4) { + tmp = (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)]; + buf[curByte++] = (tmp >> 16) & 0xff; + buf[curByte++] = (tmp >> 8) & 0xff; + buf[curByte++] = tmp & 0xff; + } + + if (placeHoldersLen === 2) { + tmp = (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4); + buf[curByte++] = tmp & 0xff; + } else if (placeHoldersLen === 1) { + tmp = (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2); + buf[curByte++] = (tmp >> 8) & 0xff; + buf[curByte++] = tmp & 0xff; + } + + return buf; + }, + fromUint8Array(buf: Uint8Array): string { + const maxChunkLength: number = 16383; // Must be multiple of 3 + + const len: number = buf.length; + + const extraBytes: number = len % 3; // If we have 1 byte left, pad 2 bytes + + const len2: number = len - extraBytes; + + const parts: string[] = new Array( + Math.ceil(len2 / maxChunkLength) + (extraBytes ? 1 : 0), + ); + + let curChunk: number = 0; + let chunkEnd: number; + + // Go through the array every three bytes, we'll deal with trailing stuff later + for (let i: number = 0; i < len2; i += maxChunkLength) { + chunkEnd = i + maxChunkLength; + parts[curChunk++] = encodeChunk( + buf, + i, + chunkEnd > len2 ? len2 : chunkEnd, + ); + } + + let tmp: number; + + // Pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = buf[len2]; + parts[curChunk] = lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f]; + if (!urlsafe) parts[curChunk] += "=="; + } else if (extraBytes === 2) { + tmp = (buf[len2] << 8) | (buf[len2 + 1] & 0xff); + parts[curChunk] = lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3f] + + lookup[(tmp << 2) & 0x3f]; + if (!urlsafe) parts[curChunk] += "="; + } + + return parts.join(""); + }, + }; +} diff --git a/vendor/deno.land/x/base64@v0.2.1/base64url.ts b/vendor/deno.land/x/base64@v0.2.1/base64url.ts new file mode 100644 index 0000000..37f8127 --- /dev/null +++ b/vendor/deno.land/x/base64@v0.2.1/base64url.ts @@ -0,0 +1,17 @@ +import { init } from "./base.ts"; + +const lookup: string[] = []; +const revLookup: number[] = []; +const code: string = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +for (let i: number = 0, l = code.length; i < l; ++i) { + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; +} + +export const { byteLength, toUint8Array, fromUint8Array } = init( + lookup, + revLookup, + true, +); diff --git a/vendor/deno.land/x/base64@v0.2.1/mod.ts b/vendor/deno.land/x/base64@v0.2.1/mod.ts new file mode 100644 index 0000000..b00b956 --- /dev/null +++ b/vendor/deno.land/x/base64@v0.2.1/mod.ts @@ -0,0 +1,21 @@ +import { init } from "./base.ts"; + +const lookup: string[] = []; +const revLookup: number[] = []; +const code: string = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +for (let i: number = 0, l = code.length; i < l; ++i) { + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; +} + +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup["-".charCodeAt(0)] = 62; +revLookup["_".charCodeAt(0)] = 63; + +export const { byteLength, toUint8Array, fromUint8Array } = init( + lookup, + revLookup, +); diff --git a/vendor/denopkg.com/chiefbiiko/sha1@master/deps.ts b/vendor/denopkg.com/chiefbiiko/sha1@master/deps.ts new file mode 100644 index 0000000..91e354e --- /dev/null +++ b/vendor/denopkg.com/chiefbiiko/sha1@master/deps.ts @@ -0,0 +1,4 @@ +export { + encode, + decode +} from "https://denopkg.com/chiefbiiko/std-encoding@v1.1.1/mod.ts"; \ No newline at end of file diff --git a/vendor/denopkg.com/chiefbiiko/sha1@master/mod.ts b/vendor/denopkg.com/chiefbiiko/sha1@master/mod.ts new file mode 100644 index 0000000..1209292 --- /dev/null +++ b/vendor/denopkg.com/chiefbiiko/sha1@master/mod.ts @@ -0,0 +1,191 @@ +import { encode, decode } from "./deps.ts"; + +function rotl(x: number, n: number): number { + return (x << n) | (x >>> (32 - n)); +} + +/** Byte length of a SHA1 digest. */ +export const BYTES: number = 20; + +/** A class representation of the SHA1 algorithm. */ +export class SHA1 { + readonly hashSize: number = BYTES; + + private _buf: Uint8Array = new Uint8Array(64); + private _bufIdx!: number; + private _count!: Uint32Array; + private _K: Uint32Array = new Uint32Array([0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]); + private _H!: Uint32Array; + private _finalized!: boolean; + + /** Creates a SHA1 instance. */ + constructor() { + this.init(); + } + + /** Reduces the four input numbers to a single one. */ + protected static F(t: number, b: number, c: number, d: number): number { + if (t <= 19) { + return (b & c) | (~b & d); + } else if (t <= 39) { + return b ^ c ^ d; + } else if (t <= 59) { + return (b & c) | (b & d) | (c & d); + } else { + return b ^ c ^ d; + } + } + + /** Initializes a hash instance. */ + init(): SHA1 { + // prettier-ignore + this._H = new Uint32Array([ + 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 + ]); + + this._bufIdx = 0; + this._count = new Uint32Array(2); + this._buf.fill(0); + this._finalized = false; + + return this; + } + + /** Updates a hash with additional message data. */ + update(msg: string | Uint8Array, inputEncoding?: string): SHA1 { + if (msg === null) { + throw new TypeError("msg must be a string or Uint8Array."); + } else if (typeof msg === "string") { + msg = encode(msg, inputEncoding) as Uint8Array; + } + + // process the msg as many times as possible, the rest is stored in the buffer + // message is processed in 512 bit (64 byte chunks) + for (let i: number = 0; i < msg.length; i++) { + this._buf[this._bufIdx++] = msg[i]; + if (this._bufIdx === 64) { + this.transform(); + this._bufIdx = 0; + } + } + + // counter update (number of message bits) + const c: Uint32Array = this._count; + + if ((c[0] += msg.length << 3) < msg.length << 3) { + c[1]++; + } + + c[1] += msg.length >>> 29; + + return this; + } + + /** Finalizes a hash with additional message data. */ + digest(outputEncoding?: string): string | Uint8Array { + if (this._finalized) { + throw new Error("digest has already been called.") + } + + this._finalized = true; + + // append '1' + const b: Uint8Array = this._buf; + let idx: number = this._bufIdx; + b[idx++] = 0x80; + + // zeropad up to byte pos 56 + while (idx !== 56) { + if (idx === 64) { + this.transform(); + idx = 0; + } + b[idx++] = 0; + } + + // append length in bits + const c: Uint32Array = this._count; + + b[56] = (c[1] >>> 24) & 0xff; + b[57] = (c[1] >>> 16) & 0xff; + b[58] = (c[1] >>> 8) & 0xff; + b[59] = (c[1] >>> 0) & 0xff; + b[60] = (c[0] >>> 24) & 0xff; + b[61] = (c[0] >>> 16) & 0xff; + b[62] = (c[0] >>> 8) & 0xff; + b[63] = (c[0] >>> 0) & 0xff; + + this.transform(); + + // return the hash as byte array (20 bytes) + const hash: Uint8Array = new Uint8Array(BYTES); + + for (let i: number = 0; i < 5; i++) { + hash[(i << 2) + 0] = (this._H[i] >>> 24) & 0xff; + hash[(i << 2) + 1] = (this._H[i] >>> 16) & 0xff; + hash[(i << 2) + 2] = (this._H[i] >>> 8) & 0xff; + hash[(i << 2) + 3] = (this._H[i] >>> 0) & 0xff; + } + + // clear internal states and prepare for new hash + this.init(); + + return outputEncoding ? decode(hash, outputEncoding) : hash; + } + + /** Performs one transformation cycle. */ + private transform(): void { + const h: Uint32Array = this._H; + let a: number = h[0]; + let b: number = h[1]; + let c: number = h[2]; + let d: number = h[3]; + let e: number = h[4]; + + // convert byte buffer to words + const w: Uint32Array = new Uint32Array(80); + + for (let i: number = 0; i < 16; i++) { + w[i] = + this._buf[(i << 2) + 3] | + (this._buf[(i << 2) + 2] << 8) | + (this._buf[(i << 2) + 1] << 16) | + (this._buf[i << 2] << 24); + } + + for (let t: number = 0; t < 80; t++) { + if (t >= 16) { + w[t] = rotl(w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16], 1); + } + + const tmp: number = + (rotl(a, 5) + + SHA1.F(t, b, c, d) + + e + + w[t] + + this._K[Math.floor(t / 20)]) | + 0; + + e = d; + d = c; + c = rotl(b, 30); + b = a; + a = tmp; + } + + h[0] = (h[0] + a) | 0; + h[1] = (h[1] + b) | 0; + h[2] = (h[2] + c) | 0; + h[3] = (h[3] + d) | 0; + h[4] = (h[4] + e) | 0; + } +} + +/** Generates a SHA1 hash of the input data. */ +export function sha1( + msg: string | Uint8Array, + inputEncoding?: string, + outputEncoding?: string +): string | Uint8Array { + return new SHA1().update(msg, inputEncoding).digest(outputEncoding); +} diff --git a/vendor/denopkg.com/chiefbiiko/std-encoding@v1.1.1/mod.ts b/vendor/denopkg.com/chiefbiiko/std-encoding@v1.1.1/mod.ts new file mode 100644 index 0000000..1cef763 --- /dev/null +++ b/vendor/denopkg.com/chiefbiiko/std-encoding@v1.1.1/mod.ts @@ -0,0 +1,56 @@ +import * as base64 from "https://deno.land/x/base64@v0.2.1/mod.ts"; +import * as base64url from "https://deno.land/x/base64@v0.2.1/base64url.ts"; + +const decoder: TextDecoder = new TextDecoder(); +const encoder: TextEncoder = new TextEncoder(); + +/** Serializes a Uint8Array to a hexadecimal string. */ +function toHexString(buf: Uint8Array): string { + return buf.reduce( + (hex: string, byte: number): string => + `${hex}${byte < 16 ? "0" : ""}${byte.toString(16)}`, + "", + ); +} + +/** Deserializes a Uint8Array from a hexadecimal string. */ +function fromHexString(hex: string): Uint8Array { + const len: number = hex.length; + if (len % 2 || !/^[0-9a-fA-F]+$/.test(hex)) { + throw new TypeError("Invalid hex string."); + } + hex = hex.toLowerCase(); + const buf: Uint8Array = new Uint8Array(Math.floor(len / 2)); + const end: number = len / 2; + for (let i: number = 0; i < end; ++i) { + buf[i] = parseInt(hex.substr(i * 2, 2), 16); + } + return buf; +} + +/** Decodes a Uint8Array to utf8-, base64-, or hex-encoded string. */ +export function decode(buf: Uint8Array, encoding: string = "utf8"): string { + if (/^utf-?8$/i.test(encoding)) { + return decoder.decode(buf); + } else if (/^base64$/i.test(encoding)) { + return base64.fromUint8Array(buf); + } else if (/^base64url$/i.test(encoding)) { + return base64url.fromUint8Array(buf); + } else if (/^hex(?:adecimal)?$/i.test(encoding)) { + return toHexString(buf); + } else { + throw new TypeError("Unsupported string encoding."); + } +} + +export function encode(str: string, encoding: string = "utf8"): Uint8Array { + if (/^utf-?8$/i.test(encoding)) { + return encoder.encode(str); + } else if (/^base64(?:url)?$/i.test(encoding)) { + return base64.toUint8Array(str); + } else if (/^hex(?:adecimal)?$/i.test(encoding)) { + return fromHexString(str); + } else { + throw new TypeError("Unsupported string encoding."); + } +} diff --git a/vendor/import_map.json b/vendor/import_map.json new file mode 100644 index 0000000..dcbdeb0 --- /dev/null +++ b/vendor/import_map.json @@ -0,0 +1,8 @@ +{ + "imports": { + "https://denopkg.com/chiefbiiko/sha1/mod.ts": "./denopkg.com/chiefbiiko/sha1@master/mod.ts", + "https://deno.land/std/testing/asserts.ts": "./deno.land/std@0.191.0/testing/asserts.ts", + "https://deno.land/": "./deno.land/", + "https://denopkg.com/": "./denopkg.com/" + } +}