From ed8773854a7cc8a20a32361017cfbdec28fbe644 Mon Sep 17 00:00:00 2001 From: Kyle Loveless Date: Fri, 22 Nov 2024 16:31:38 -0600 Subject: [PATCH] vendor @std/fmt --- deno.json | 4 +- deno.lock | 16 + vendor/jsr.io/@std/fmt/1.0.3/bytes.ts | 209 +++++ vendor/jsr.io/@std/fmt/1.0.3/colors.ts | 1002 ++++++++++++++++++++++ vendor/jsr.io/@std/fmt/1.0.3/duration.ts | 176 ++++ vendor/jsr.io/@std/fmt/1.0.3/printf.ts | 998 +++++++++++++++++++++ vendor/jsr.io/@std/fmt/1.0.3_meta.json | 60 ++ vendor/jsr.io/@std/fmt/meta.json | 55 ++ 8 files changed, 2519 insertions(+), 1 deletion(-) create mode 100644 deno.lock create mode 100644 vendor/jsr.io/@std/fmt/1.0.3/bytes.ts create mode 100644 vendor/jsr.io/@std/fmt/1.0.3/colors.ts create mode 100644 vendor/jsr.io/@std/fmt/1.0.3/duration.ts create mode 100644 vendor/jsr.io/@std/fmt/1.0.3/printf.ts create mode 100644 vendor/jsr.io/@std/fmt/1.0.3_meta.json create mode 100644 vendor/jsr.io/@std/fmt/meta.json diff --git a/deno.json b/deno.json index 6a49bb7..d971fe6 100644 --- a/deno.json +++ b/deno.json @@ -3,5 +3,7 @@ "dev": "deno run --watch main.ts" }, "imports": { - } + "@std/fmt": "jsr:@std/fmt@^1.0.3" + }, + "vendor": true } diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..e658511 --- /dev/null +++ b/deno.lock @@ -0,0 +1,16 @@ +{ + "version": "4", + "specifiers": { + "jsr:@std/fmt@^1.0.3": "1.0.3" + }, + "jsr": { + "@std/fmt@1.0.3": { + "integrity": "97765c16aa32245ff4e2204ecf7d8562496a3cb8592340a80e7e554e0bb9149f" + } + }, + "workspace": { + "dependencies": [ + "jsr:@std/fmt@^1.0.3" + ] + } +} diff --git a/vendor/jsr.io/@std/fmt/1.0.3/bytes.ts b/vendor/jsr.io/@std/fmt/1.0.3/bytes.ts new file mode 100644 index 0000000..a86923d --- /dev/null +++ b/vendor/jsr.io/@std/fmt/1.0.3/bytes.ts @@ -0,0 +1,209 @@ +// Copyright 2014-2021 Sindre Sorhus. All rights reserved. MIT license. +// Copyright 2021 Yoshiya Hinosawa. All rights reserved. MIT license. +// Copyright 2021 Giuseppe Eletto. All rights reserved. MIT license. +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +/** + * Convert bytes to a human-readable string: 1337 → 1.34 kB + * + * Based on {@link https://github.com/sindresorhus/pretty-bytes | pretty-bytes}. + * A utility for displaying file sizes for humans. + * + * ```ts + * import { format } from "@std/fmt/bytes"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(format(1337), "1.34 kB"); + * assertEquals(format(100), "100 B"); + * ``` + * @module + */ + +type LocaleOptions = { + minimumFractionDigits?: number; + maximumFractionDigits?: number; +}; + +/** Options for {@linkcode format}. */ +export interface FormatOptions { + /** + * Uses bits representation. + * + * @default {false} + */ + bits?: boolean; + /** + * Uses binary bytes (e.g. kibibyte). + * + * @default {false} + */ + binary?: boolean; + /** + * Include plus sign for positive numbers. + * + * @default {false} + */ + signed?: boolean; + /** + * Uses localized number formatting. If it is set to true, uses default + * locale on the system. If it's set to string, uses that locale. The given + * string should be a + * {@link https://en.wikipedia.org/wiki/IETF_language_tag | BCP 47 language tag}. + * You can also give the list of language tags. + */ + locale?: boolean | string | string[]; + /** + * The minimum number of fraction digits to display. If neither + * {@linkcode minimumFractionDigits} or {@linkcode maximumFractionDigits} + * are set. + * + * @default {3} + */ + minimumFractionDigits?: number; + /** + * The maximum number of fraction digits to display. If neither + * {@linkcode minimumFractionDigits} or {@linkcode maximumFractionDigits} + * are set. + * + * @default {3} + */ + maximumFractionDigits?: number; +} + +/** + * Convert bytes to a human-readable string: 1337 → 1.34 kB + * + * Based on {@link https://github.com/sindresorhus/pretty-bytes | pretty-bytes}. + * A utility for displaying file sizes for humans. + * + * @param num The bytes value to format + * @param options The options for formatting + * @returns The formatted string + * + * @example Basic usage + * ```ts + * import { format } from "@std/fmt/bytes"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(format(1337), "1.34 kB"); + * assertEquals(format(100), "100 B"); + * ``` + * + * @example Include bits representation + * + * ```ts + * import { format } from "@std/fmt/bytes"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(format(1337, { bits: true }), "1.34 kbit"); + * ``` + * + * @example Include sign + * + * ```ts + * import { format } from "@std/fmt/bytes"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(format(42, { signed: true }), "+42 B"); + * assertEquals(format(-42, { signed: true }), "-42 B"); + * ``` + * + * @example Change locale + * + * ```ts + * import { format } from "@std/fmt/bytes"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(format(1337, { locale: "de" }), "1,34 kB"); + * ``` + */ +export function format( + num: number, + options: FormatOptions = {}, +): string { + if (!Number.isFinite(num)) { + throw new TypeError(`Expected a finite number, got ${typeof num}: ${num}`); + } + + const UNITS_FIRSTLETTER = (options.bits ? "b" : "B") + "kMGTPEZY"; + + if (options.signed && num === 0) { + return ` 0 ${UNITS_FIRSTLETTER[0]}`; + } + + const prefix = num < 0 ? "-" : (options.signed ? "+" : ""); + num = Math.abs(num); + + const localeOptions = getLocaleOptions(options); + + if (num < 1) { + const numberString = toLocaleString(num, options.locale, localeOptions); + return prefix + numberString + " " + UNITS_FIRSTLETTER[0]; + } + + const exponent = Math.min( + Math.floor( + options.binary ? Math.log(num) / Math.log(1024) : Math.log10(num) / 3, + ), + UNITS_FIRSTLETTER.length - 1, + ); + num /= Math.pow(options.binary ? 1024 : 1000, exponent); + + if (!localeOptions) { + num = Number(num.toPrecision(3)); + } + + const numberString = toLocaleString( + num, + options.locale, + localeOptions, + ); + + let unit = UNITS_FIRSTLETTER[exponent]; + if (exponent > 0) { + unit += options.binary ? "i" : ""; + unit += options.bits ? "bit" : "B"; + } + + return prefix + numberString + " " + unit; +} + +function getLocaleOptions( + { maximumFractionDigits, minimumFractionDigits }: FormatOptions, +): LocaleOptions | undefined { + if ( + maximumFractionDigits === undefined && minimumFractionDigits === undefined + ) { + return; + } + + const ret: LocaleOptions = {}; + if (maximumFractionDigits !== undefined) { + ret.maximumFractionDigits = maximumFractionDigits; + } + if (minimumFractionDigits !== undefined) { + ret.minimumFractionDigits = minimumFractionDigits; + } + return ret; +} + +/** + * Formats the given number using `Number#toLocaleString`. + * - If locale is a string, the value is expected to be a locale-key (for example: `de`). + * - If locale is true, the system default locale is used for translation. + * - If no value for locale is specified, the number is returned unmodified. + */ +function toLocaleString( + num: number, + locale: boolean | string | string[] | undefined, + options: LocaleOptions | undefined, +): string { + if (typeof locale === "string" || Array.isArray(locale)) { + return num.toLocaleString(locale, options); + } else if (locale === true || options !== undefined) { + return num.toLocaleString(undefined, options); + } + + return num.toString(); +} diff --git a/vendor/jsr.io/@std/fmt/1.0.3/colors.ts b/vendor/jsr.io/@std/fmt/1.0.3/colors.ts new file mode 100644 index 0000000..1ea2181 --- /dev/null +++ b/vendor/jsr.io/@std/fmt/1.0.3/colors.ts @@ -0,0 +1,1002 @@ +// Copyright 2018-2024 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. + * + * > [!IMPORTANT] + * > If printing directly to the console, it's recommended to style console + * > output using CSS (guide + * > {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/console#styling_console_output | here}). + * + * This module supports `NO_COLOR` environmental variable disabling any coloring + * if `NO_COLOR` is set. + * + * ```ts no-assert + * import { + * bgBlue, + * bgRgb24, + * bgRgb8, + * bold, + * italic, + * red, + * rgb24, + * rgb8, + * } from "@std/fmt/colors"; + * + * 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 + : false; + +interface Code { + open: string; + close: string; + regexp: RegExp; +} + +/** RGB 8-bits per channel. Each in range `0->255` or `0x00->0xff` */ +export interface Rgb { + /** Red component value */ + r: number; + /** Green component value */ + g: number; + /** Blue component value */ + b: number; +} + +let enabled = !noColor; + +/** + * Enable or disable text color when styling. + * + * `@std/fmt/colors` automatically detects NO_COLOR environmental variable + * and disables text color. Use this API only when the automatic detection + * doesn't work. + * + * @example Usage + * ```ts no-assert + * import { setColorEnabled } from "@std/fmt/colors"; + * + * // Disable text color + * setColorEnabled(false); + * + * // Enable text color + * setColorEnabled(true); + * ``` + * + * @param value The boolean value to enable or disable text color + */ +export function setColorEnabled(value: boolean) { + if (Deno?.noColor) { + return; + } + + enabled = value; +} + +/** + * Get whether text color change is enabled or disabled. + * + * @example Usage + * ```ts no-assert + * import { getColorEnabled } from "@std/fmt/colors"; + * + * console.log(getColorEnabled()); // true if enabled, false if disabled + * ``` + * @returns `true` if text color is enabled, `false` otherwise + */ +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 The text to apply color settings to + * @param code The 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. + * + * @example Usage + * ```ts no-assert + * import { reset } from "@std/fmt/colors"; + * + * console.log(reset("Hello, world!")); + * ``` + * + * @param str The text to reset + * @returns The text with reset color + */ +export function reset(str: string): string { + return run(str, code([0], 0)); +} + +/** + * Make the text bold. + * + * @example Usage + * ```ts no-assert + * import { bold } from "@std/fmt/colors"; + * + * console.log(bold("Hello, world!")); + * ``` + * + * @param str The text to make bold + * @returns The bold text + */ +export function bold(str: string): string { + return run(str, code([1], 22)); +} + +/** + * The text emits only a small amount of light. + * + * @example Usage + * ```ts no-assert + * import { dim } from "@std/fmt/colors"; + * + * console.log(dim("Hello, world!")); + * ``` + * + * @param str The text to dim + * @returns The dimmed text + * + * Warning: Not all terminal emulators support `dim`. + * For compatibility across all terminals, use {@linkcode gray} or {@linkcode brightBlack} instead. + */ +export function dim(str: string): string { + return run(str, code([2], 22)); +} + +/** + * Make the text italic. + * + * @example Usage + * ```ts no-assert + * import { italic } from "@std/fmt/colors"; + * + * console.log(italic("Hello, world!")); + * ``` + * + * @param str The text to make italic + * @returns The italic text + */ +export function italic(str: string): string { + return run(str, code([3], 23)); +} + +/** + * Make the text underline. + * + * @example Usage + * ```ts no-assert + * import { underline } from "@std/fmt/colors"; + * + * console.log(underline("Hello, world!")); + * ``` + * + * @param str The text to underline + * @returns The underlined text + */ +export function underline(str: string): string { + return run(str, code([4], 24)); +} + +/** + * Invert background color and text color. + * + * @example Usage + * ```ts no-assert + * import { inverse } from "@std/fmt/colors"; + * + * console.log(inverse("Hello, world!")); + * ``` + * + * @param str The text to invert its color + * @returns The inverted text + */ +export function inverse(str: string): string { + return run(str, code([7], 27)); +} + +/** + * Make the text hidden. + * + * @example Usage + * ```ts no-assert + * import { hidden } from "@std/fmt/colors"; + * + * console.log(hidden("Hello, world!")); + * ``` + * + * @param str The text to hide + * @returns The hidden text + */ +export function hidden(str: string): string { + return run(str, code([8], 28)); +} + +/** + * Put horizontal line through the center of the text. + * + * @example Usage + * ```ts no-assert + * import { strikethrough } from "@std/fmt/colors"; + * + * console.log(strikethrough("Hello, world!")); + * ``` + * + * @param str The text to strike through + * @returns The text with horizontal line through the center + */ +export function strikethrough(str: string): string { + return run(str, code([9], 29)); +} + +/** + * Set text color to black. + * + * @example Usage + * ```ts no-assert + * import { black } from "@std/fmt/colors"; + * + * console.log(black("Hello, world!")); + * ``` + * + * @param str The text to make black + * @returns The black text + */ +export function black(str: string): string { + return run(str, code([30], 39)); +} + +/** + * Set text color to red. + * + * @example Usage + * ```ts no-assert + * import { red } from "@std/fmt/colors"; + * + * console.log(red("Hello, world!")); + * ``` + * + * @param str The text to make red + * @returns The red text + */ +export function red(str: string): string { + return run(str, code([31], 39)); +} + +/** + * Set text color to green. + * + * @example Usage + * ```ts no-assert + * import { green } from "@std/fmt/colors"; + * + * console.log(green("Hello, world!")); + * ``` + * + * @param str The text to make green + * @returns The green text + */ +export function green(str: string): string { + return run(str, code([32], 39)); +} + +/** + * Set text color to yellow. + * + * @example Usage + * ```ts no-assert + * import { yellow } from "@std/fmt/colors"; + * + * console.log(yellow("Hello, world!")); + * ``` + * + * @param str The text to make yellow + * @returns The yellow text + */ +export function yellow(str: string): string { + return run(str, code([33], 39)); +} + +/** + * Set text color to blue. + * + * @example Usage + * ```ts no-assert + * import { blue } from "@std/fmt/colors"; + * + * console.log(blue("Hello, world!")); + * ``` + * + * @param str The text to make blue + * @returns The blue text + */ +export function blue(str: string): string { + return run(str, code([34], 39)); +} + +/** + * Set text color to magenta. + * + * @example Usage + * ```ts no-assert + * import { magenta } from "@std/fmt/colors"; + * + * console.log(magenta("Hello, world!")); + * ``` + * + * @param str The text to make magenta + * @returns The magenta text + */ +export function magenta(str: string): string { + return run(str, code([35], 39)); +} + +/** + * Set text color to cyan. + * + * @example Usage + * ```ts no-assert + * import { cyan } from "@std/fmt/colors"; + * + * console.log(cyan("Hello, world!")); + * ``` + * + * @param str The text to make cyan + * @returns The cyan text + */ +export function cyan(str: string): string { + return run(str, code([36], 39)); +} + +/** + * Set text color to white. + * + * @example Usage + * ```ts no-assert + * import { white } from "@std/fmt/colors"; + * + * console.log(white("Hello, world!")); + * ``` + * + * @param str The text to make white + * @returns The white text + */ +export function white(str: string): string { + return run(str, code([37], 39)); +} + +/** + * Set text color to gray. + * + * @example Usage + * ```ts no-assert + * import { gray } from "@std/fmt/colors"; + * + * console.log(gray("Hello, world!")); + * ``` + * + * @param str The text to make gray + * @returns The gray text + */ +export function gray(str: string): string { + return brightBlack(str); +} + +/** + * Set text color to bright black. + * + * @example Usage + * ```ts no-assert + * import { brightBlack } from "@std/fmt/colors"; + * + * console.log(brightBlack("Hello, world!")); + * ``` + * + * @param str The text to make bright black + * @returns The bright black text + */ +export function brightBlack(str: string): string { + return run(str, code([90], 39)); +} + +/** + * Set text color to bright red. + * + * @example Usage + * ```ts no-assert + * import { brightRed } from "@std/fmt/colors"; + * + * console.log(brightRed("Hello, world!")); + * ``` + * + * @param str The text to make bright red + * @returns The bright red text + */ +export function brightRed(str: string): string { + return run(str, code([91], 39)); +} + +/** + * Set text color to bright green. + * + * @example Usage + * ```ts no-assert + * import { brightGreen } from "@std/fmt/colors"; + * + * console.log(brightGreen("Hello, world!")); + * ``` + * + * @param str The text to make bright green + * @returns The bright green text + */ +export function brightGreen(str: string): string { + return run(str, code([92], 39)); +} + +/** + * Set text color to bright yellow. + * + * @example Usage + * ```ts no-assert + * import { brightYellow } from "@std/fmt/colors"; + * + * console.log(brightYellow("Hello, world!")); + * ``` + * + * @param str The text to make bright yellow + * @returns The bright yellow text + */ +export function brightYellow(str: string): string { + return run(str, code([93], 39)); +} + +/** + * Set text color to bright blue. + * + * @example Usage + * ```ts no-assert + * import { brightBlue } from "@std/fmt/colors"; + * + * console.log(brightBlue("Hello, world!")); + * ``` + * + * @param str The text to make bright blue + * @returns The bright blue text + */ +export function brightBlue(str: string): string { + return run(str, code([94], 39)); +} + +/** + * Set text color to bright magenta. + * + * @example Usage + * ```ts no-assert + * import { brightMagenta } from "@std/fmt/colors"; + * + * console.log(brightMagenta("Hello, world!")); + * ``` + * + * @param str The text to make bright magenta + * @returns The bright magenta text + */ +export function brightMagenta(str: string): string { + return run(str, code([95], 39)); +} + +/** + * Set text color to bright cyan. + * + * @example Usage + * ```ts no-assert + * import { brightCyan } from "@std/fmt/colors"; + * + * console.log(brightCyan("Hello, world!")); + * ``` + * + * @param str The text to make bright cyan + * @returns The bright cyan text + */ +export function brightCyan(str: string): string { + return run(str, code([96], 39)); +} + +/** + * Set text color to bright white. + * + * @example Usage + * ```ts no-assert + * import { brightWhite } from "@std/fmt/colors"; + * + * console.log(brightWhite("Hello, world!")); + * ``` + * + * @param str The text to make bright white + * @returns The bright white text + */ +export function brightWhite(str: string): string { + return run(str, code([97], 39)); +} + +/** + * Set background color to black. + * + * @example Usage + * ```ts no-assert + * import { bgBlack } from "@std/fmt/colors"; + * + * console.log(bgBlack("Hello, world!")); + * ``` + * + * @param str The text to make its background black + * @returns The text with black background + */ +export function bgBlack(str: string): string { + return run(str, code([40], 49)); +} + +/** + * Set background color to red. + * + * @example Usage + * ```ts no-assert + * import { bgRed } from "@std/fmt/colors"; + * + * console.log(bgRed("Hello, world!")); + * ``` + * + * @param str The text to make its background red + * @returns The text with red background + */ +export function bgRed(str: string): string { + return run(str, code([41], 49)); +} + +/** + * Set background color to green. + * + * @example Usage + * ```ts no-assert + * import { bgGreen } from "@std/fmt/colors"; + * + * console.log(bgGreen("Hello, world!")); + * ``` + * + * @param str The text to make its background green + * @returns The text with green background + */ +export function bgGreen(str: string): string { + return run(str, code([42], 49)); +} + +/** + * Set background color to yellow. + * + * @example Usage + * ```ts no-assert + * import { bgYellow } from "@std/fmt/colors"; + * + * console.log(bgYellow("Hello, world!")); + * ``` + * + * @param str The text to make its background yellow + * @returns The text with yellow background + */ +export function bgYellow(str: string): string { + return run(str, code([43], 49)); +} + +/** + * Set background color to blue. + * + * @example Usage + * ```ts no-assert + * import { bgBlue } from "@std/fmt/colors"; + * + * console.log(bgBlue("Hello, world!")); + * ``` + * + * @param str The text to make its background blue + * @returns The text with blue background + */ +export function bgBlue(str: string): string { + return run(str, code([44], 49)); +} + +/** + * Set background color to magenta. + * + * @example Usage + * ```ts no-assert + * import { bgMagenta } from "@std/fmt/colors"; + * + * console.log(bgMagenta("Hello, world!")); + * ``` + * + * @param str The text to make its background magenta + * @returns The text with magenta background + */ +export function bgMagenta(str: string): string { + return run(str, code([45], 49)); +} + +/** + * Set background color to cyan. + * + * @example Usage + * ```ts no-assert + * import { bgCyan } from "@std/fmt/colors"; + * + * console.log(bgCyan("Hello, world!")); + * ``` + * + * @param str The text to make its background cyan + * @returns The text with cyan background + */ +export function bgCyan(str: string): string { + return run(str, code([46], 49)); +} + +/** + * Set background color to white. + * + * @example Usage + * ```ts no-assert + * import { bgWhite } from "@std/fmt/colors"; + * + * console.log(bgWhite("Hello, world!")); + * ``` + * + * @param str The text to make its background white + * @returns The text with white background + */ +export function bgWhite(str: string): string { + return run(str, code([47], 49)); +} + +/** + * Set background color to bright black. + * + * @example Usage + * ```ts no-assert + * import { bgBrightBlack } from "@std/fmt/colors"; + * + * console.log(bgBrightBlack("Hello, world!")); + * ``` + * + * @param str The text to make its background bright black + * @returns The text with bright black background + */ +export function bgBrightBlack(str: string): string { + return run(str, code([100], 49)); +} + +/** + * Set background color to bright red. + * + * @example Usage + * ```ts no-assert + * import { bgBrightRed } from "@std/fmt/colors"; + * + * console.log(bgBrightRed("Hello, world!")); + * ``` + * + * @param str The text to make its background bright red + * @returns The text with bright red background + */ +export function bgBrightRed(str: string): string { + return run(str, code([101], 49)); +} + +/** + * Set background color to bright green. + * + * @example Usage + * ```ts no-assert + * import { bgBrightGreen } from "@std/fmt/colors"; + * + * console.log(bgBrightGreen("Hello, world!")); + * ``` + * + * @param str The text to make its background bright green + * @returns The text with bright green background + */ +export function bgBrightGreen(str: string): string { + return run(str, code([102], 49)); +} + +/** + * Set background color to bright yellow. + * + * @example Usage + * ```ts no-assert + * import { bgBrightYellow } from "@std/fmt/colors"; + * + * console.log(bgBrightYellow("Hello, world!")); + * ``` + * + * @param str The text to make its background bright yellow + * @returns The text with bright yellow background + */ +export function bgBrightYellow(str: string): string { + return run(str, code([103], 49)); +} + +/** + * Set background color to bright blue. + * + * @example Usage + * ```ts no-assert + * import { bgBrightBlue } from "@std/fmt/colors"; + * + * console.log(bgBrightBlue("Hello, world!")); + * ``` + * + * @param str The text to make its background bright blue + * @returns The text with bright blue background + */ +export function bgBrightBlue(str: string): string { + return run(str, code([104], 49)); +} + +/** + * Set background color to bright magenta. + * + * @example Usage + * ```ts no-assert + * import { bgBrightMagenta } from "@std/fmt/colors"; + * + * console.log(bgBrightMagenta("Hello, world!")); + * ``` + * + * @param str The text to make its background bright magenta + * @returns The text with bright magenta background + */ +export function bgBrightMagenta(str: string): string { + return run(str, code([105], 49)); +} + +/** + * Set background color to bright cyan. + * + * @example Usage + * ```ts no-assert + * import { bgBrightCyan } from "@std/fmt/colors"; + * + * console.log(bgBrightCyan("Hello, world!")); + * ``` + * + * @param str The text to make its background bright cyan + * @returns The text with bright cyan background + */ +export function bgBrightCyan(str: string): string { + return run(str, code([106], 49)); +} + +/** + * Set background color to bright white. + * + * @example Usage + * ```ts no-assert + * import { bgBrightWhite } from "@std/fmt/colors"; + * + * console.log(bgBrightWhite("Hello, world!")); + * ``` + * + * @param str The text to make its background bright white + * @returns The text with bright white background + */ +export function bgBrightWhite(str: string): string { + return run(str, code([107], 49)); +} + +/* Special Color Sequences */ + +/** + * Clam and truncate color codes + * @param n The input number + * @param max The number to truncate to + * @param min The 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 + * + * @example Usage + * ```ts no-assert + * import { rgb8 } from "@std/fmt/colors"; + * + * console.log(rgb8("Hello, world!", 42)); + * ``` + * + * @param str The text color to apply paletted 8bit colors to + * @param color The color code + * @returns The text with paletted 8bit color + */ +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 + * + * @example Usage + * ```ts no-assert + * import { bgRgb8 } from "@std/fmt/colors"; + * + * console.log(bgRgb8("Hello, world!", 42)); + * ``` + * + * @param str The text color to apply paletted 8bit background colors to + * @param color code + * @returns The text with paletted 8bit background color + */ +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`. + * + * @example To produce the color magenta: + * ```ts no-assert + * import { rgb24 } from "@std/fmt/colors"; + * + * rgb24("foo", 0xff00ff); + * rgb24("foo", {r: 255, g: 0, b: 255}); + * ``` + * @param str The text color to apply 24bit rgb to + * @param color The color code + * @returns The text with 24bit rgb color + */ +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`. + * + * @example To produce the color magenta: + * ```ts no-assert + * import { bgRgb24 } from "@std/fmt/colors"; + * + * bgRgb24("foo", 0xff00ff); + * bgRgb24("foo", {r: 255, g: 0, b: 255}); + * ``` + * @param str The text color to apply 24bit rgb to + * @param color The color code + * @returns The text with 24bit rgb color + */ +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-TXZcf-nq-uy=><~]))", + ].join("|"), + "g", +); + +/** + * Remove ANSI escape codes from the string. + * + * @example Usage + * ```ts no-assert + * import { stripAnsiCode, red } from "@std/fmt/colors"; + * + * console.log(stripAnsiCode(red("Hello, world!"))); + * ``` + * + * @param string The text to remove ANSI escape codes from + * @returns The text without ANSI escape codes + */ +export function stripAnsiCode(string: string): string { + return string.replace(ANSI_PATTERN, ""); +} diff --git a/vendor/jsr.io/@std/fmt/1.0.3/duration.ts b/vendor/jsr.io/@std/fmt/1.0.3/duration.ts new file mode 100644 index 0000000..d116340 --- /dev/null +++ b/vendor/jsr.io/@std/fmt/1.0.3/duration.ts @@ -0,0 +1,176 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +/** + * Format milliseconds to time duration. + * + * ```ts + * import { format } from "@std/fmt/duration"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(format(99674, { style: "digital" }), "00:00:01:39:674:000:000"); + * + * assertEquals(format(99674), "0d 0h 1m 39s 674ms 0µs 0ns"); + * + * assertEquals(format(99674, { ignoreZero: true }), "1m 39s 674ms"); + * + * assertEquals(format(99674, { style: "full", ignoreZero: true }), "1 minutes, 39 seconds, 674 milliseconds"); + * ``` + * @module + */ + +function addZero(num: number, digits: number) { + return String(num).padStart(digits, "0"); +} + +interface DurationObject { + d: number; + h: number; + m: number; + s: number; + ms: number; + us: number; + ns: number; +} + +const keyList: Record = { + d: "days", + h: "hours", + m: "minutes", + s: "seconds", + ms: "milliseconds", + us: "microseconds", + ns: "nanoseconds", +}; + +/** Parse milliseconds into a duration. */ +function millisecondsToDurationObject(ms: number): DurationObject { + // Duration cannot be negative + const millis = Math.abs(ms); + const millisFraction = millis.toFixed(7).slice(-7, -1); + return { + d: Math.trunc(millis / 86400000), + h: Math.trunc(millis / 3600000) % 24, + m: Math.trunc(millis / 60000) % 60, + s: Math.trunc(millis / 1000) % 60, + ms: Math.trunc(millis) % 1000, + us: +millisFraction.slice(0, 3), + ns: +millisFraction.slice(3, 6), + }; +} + +function durationArray( + duration: DurationObject, +): { type: keyof DurationObject; value: number }[] { + return [ + { type: "d", value: duration.d }, + { type: "h", value: duration.h }, + { type: "m", value: duration.m }, + { type: "s", value: duration.s }, + { type: "ms", value: duration.ms }, + { type: "us", value: duration.us }, + { type: "ns", value: duration.ns }, + ]; +} + +/** Options for {@linkcode format}. */ +export interface FormatOptions { + /** + * The style for formatting the duration. + * + * "narrow" for "0d 0h 0m 0s 0ms..." + * "digital" for "00:00:00:00:000..." + * "full" for "0 days, 0 hours, 0 minutes,..." + * + * @default {"narrow"} + */ + style?: "narrow" | "digital" | "full"; + /** + * Whether to ignore zero values. + * With style="narrow" | "full", all zero values are ignored. + * With style="digital", only values in the ends are ignored. + * + * @default {false} + */ + ignoreZero?: boolean; +} + +/** + * Format milliseconds to time duration. + * + * @example Usage + * ```ts + * import { format } from "@std/fmt/duration"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(format(99674, { style: "digital" }), "00:00:01:39:674:000:000"); + * + * assertEquals(format(99674), "0d 0h 1m 39s 674ms 0µs 0ns"); + * + * assertEquals(format(99674, { ignoreZero: true }), "1m 39s 674ms"); + * + * assertEquals(format(99674, { style: "full", ignoreZero: true }), "1 minutes, 39 seconds, 674 milliseconds"); + * ``` + * + * @param ms The milliseconds value to format + * @param options The options for formatting + * @returns The formatted string + */ +export function format( + ms: number, + options?: FormatOptions, +): string { + const { + style = "narrow", + ignoreZero = false, + } = options ?? {}; + + const duration = millisecondsToDurationObject(ms); + const durationArr = durationArray(duration); + switch (style) { + case "narrow": { + if (ignoreZero) { + return `${ + durationArr.filter((x) => x.value).map((x) => + `${x.value}${x.type === "us" ? "µs" : x.type}` + ) + .join(" ") + }`; + } + return `${ + durationArr.map((x) => `${x.value}${x.type === "us" ? "µs" : x.type}`) + .join(" ") + }`; + } + case "full": { + if (ignoreZero) { + return `${ + durationArr.filter((x) => x.value).map((x) => + `${x.value} ${keyList[x.type]}` + ).join(", ") + }`; + } + return `${ + durationArr.map((x) => `${x.value} ${keyList[x.type]}`).join(", ") + }`; + } + case "digital": { + const arr = durationArr.map((x) => + ["ms", "us", "ns"].includes(x.type) + ? addZero(x.value, 3) + : addZero(x.value, 2) + ); + if (ignoreZero) { + let cont = true; + while (cont) { + if (!Number(arr[arr.length - 1])) arr.pop(); + else cont = false; + } + } + return arr.join(":"); + } + default: { + throw new TypeError(`style must be "narrow", "full", or "digital"!`); + } + } +} diff --git a/vendor/jsr.io/@std/fmt/1.0.3/printf.ts b/vendor/jsr.io/@std/fmt/1.0.3/printf.ts new file mode 100644 index 0000000..e5b4180 --- /dev/null +++ b/vendor/jsr.io/@std/fmt/1.0.3/printf.ts @@ -0,0 +1,998 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +/** + * {@linkcode sprintf} and {@linkcode printf} for printing formatted strings to + * stdout. + * + * ```ts + * import { sprintf } from "@std/fmt/printf"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(sprintf("%d", 9), "9"); + * assertEquals(sprintf("%o", 9), "11"); + * assertEquals(sprintf("%f", 4), "4.000000"); + * assertEquals(sprintf("%.3f", 0.9999), "1.000"); + * ``` + * + * This implementation is inspired by POSIX and Golang but does not port + * implementation code. + * + * sprintf converts and formats a variable number of arguments as is specified + * by a `format string`. In it's basic form, a format string may just be a + * literal. In case arguments are meant to be formatted, a `directive` is + * contained in the format string, preceded by a '%' character: + * + * % + * + * E.g. the verb `s` indicates the directive should be replaced by the string + * representation of the argument in the corresponding position of the argument + * list. E.g.: + * + * Hello %s! + * + * applied to the arguments "World" yields "Hello World!". + * + * The meaning of the format string is modelled after [POSIX][1] format strings + * as well as well as [Golang format strings][2]. Both contain elements specific + * to the respective programming language that don't apply to JavaScript, so + * they can not be fully supported. Furthermore we implement some functionality + * that is specific to JS. + * + * ## Verbs + * + * The following verbs are supported: + * + * | Verb | Meaning | + * | ----- | -------------------------------------------------------------- | + * | `%` | print a literal percent | + * | `t` | evaluate arg as boolean, print `true` or `false` | + * | `b` | eval as number, print binary | + * | `c` | eval as number, print character corresponding to the codePoint | + * | `o` | eval as number, print octal | + * | `x X` | print as hex (ff FF), treat string as list of bytes | + * | `e E` | print number in scientific/exponent format 1.123123e+01 | + * | `f F` | print number as float with decimal point and no exponent | + * | `g G` | use %e %E or %f %F depending on size of argument | + * | `s` | interpolate string | + * | `T` | type of arg, as returned by `typeof` | + * | `v` | value of argument in 'default' format (see below) | + * | `j` | argument as formatted by `JSON.stringify` | + * | `i` | argument as formatted by `Deno.inspect` | + * | `I` | argument as formatted by `Deno.inspect` in compact format | + * + * ## Width and Precision + * + * Verbs may be modified by providing them with width and precision, either or + * both may be omitted: + * + * %9f width 9, default precision + * %.9f default width, precision 9 + * %8.9f width 8, precision 9 + * %8.f width 8, precision 0 + * + * In general, 'width' describes the minimum length of the output, while + * 'precision' limits the output. + * + * | verb | precision | + * | --------- | --------------------------------------------------------------- | + * | `t` | n/a | + * | `b c o` | n/a | + * | `x X` | n/a for number, strings are truncated to p bytes(!) | + * | `e E f F` | number of places after decimal, default 6 | + * | `g G` | set maximum number of digits | + * | `s` | truncate input | + * | `T` | truncate | + * | `v` | truncate, or depth if used with # see "'default' format", below | + * | `j` | n/a | + * + * Numerical values for width and precision can be substituted for the `*` char, + * in which case the values are obtained from the next args, e.g.: + * + * sprintf("%*.*f", 9, 8, 456.0) + * + * is equivalent to: + * + * sprintf("%9.8f", 456.0) + * + * ## Flags + * + * The effects of the verb may be further influenced by using flags to modify + * the directive: + * + * | Flag | Verb | Meaning | + * | ----- | --------- | -------------------------------------------------------------------------- | + * | `+` | numeric | always print sign | + * | `-` | all | pad to the right (left justify) | + * | `#` | | alternate format | + * | `#` | `b o x X` | prefix with `0b 0 0x` | + * | `#` | `g G` | don't remove trailing zeros | + * | `#` | `v` | use output of `inspect` instead of `toString` | + * | `' '` | | space character | + * | `' '` | `x X` | leave spaces between bytes when printing string | + * | `' '` | `d` | insert space for missing `+` sign character | + * | `0` | all | pad with zero, `-` takes precedence, sign is appended in front of padding | + * | `<` | all | format elements of the passed array according to the directive (extension) | + * + * ## 'default' format + * + * The default format used by `%v` is the result of calling `toString()` on the + * relevant argument. If the `#` flags is used, the result of calling `inspect()` + * is interpolated. In this case, the precision, if set is passed to `inspect()` + * as the 'depth' config parameter. + * + * ## Positional arguments + * + * Arguments do not need to be consumed in the order they are provided and may + * be consumed more than once. E.g.: + * + * sprintf("%[2]s %[1]s", "World", "Hello") + * + * returns "Hello World". The presence of a positional indicator resets the arg + * counter allowing args to be reused: + * + * sprintf("dec[%d]=%d hex[%[1]d]=%x oct[%[1]d]=%#o %s", 1, 255, "Third") + * + * returns `dec[1]=255 hex[1]=0xff oct[1]=0377 Third` + * + * Width and precision my also use positionals: + * + * "%[2]*.[1]*d", 1, 2 + * + * This follows the golang conventions and not POSIX. + * + * ## Errors + * + * The following errors are handled: + * + * Incorrect verb: + * + * S("%h", "") %!(BAD VERB 'h') + * + * Too few arguments: + * + * S("%d") %!(MISSING 'd')" + * + * [1]: https://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html + * [2]: https://golang.org/pkg/fmt/ + * + * @module + */ + +const State = { + PASSTHROUGH: 0, + PERCENT: 1, + POSITIONAL: 2, + PRECISION: 3, + WIDTH: 4, +} as const; + +type State = typeof State[keyof typeof State]; + +const WorP = { + WIDTH: 0, + PRECISION: 1, +} as const; + +type WorP = typeof WorP[keyof typeof WorP]; + +const F = { + sign: 1, + mantissa: 2, + fractional: 3, + esign: 4, + exponent: 5, +} as const; + +class Flags { + plus: boolean | undefined; + dash: boolean | undefined; + sharp: boolean | undefined; + space: boolean | undefined; + zero: boolean | undefined; + lessthan: boolean | undefined; + width = -1; + precision = -1; +} + +const min = Math.min; +const UNICODE_REPLACEMENT_CHARACTER = "\ufffd"; +const DEFAULT_PRECISION = 6; +const FLOAT_REGEXP = /(-?)(\d)\.?(\d*)e([+-])(\d+)/; + +class Printf { + format: string; + args: unknown[]; + i: number; + + state: State = State.PASSTHROUGH; + verb = ""; + buf = ""; + argNum = 0; + flags: Flags = new Flags(); + + haveSeen: boolean[]; + + // barf, store precision and width errors for later processing ... + tmpError: string | undefined; + + constructor(format: string, ...args: unknown[]) { + this.format = format; + this.args = args; + this.haveSeen = Array.from({ length: args.length }); + this.i = 0; + } + + doPrintf(): string { + for (; this.i < this.format.length; ++this.i) { + const c = this.format[this.i]; + switch (this.state) { + case State.PASSTHROUGH: + if (c === "%") { + this.state = State.PERCENT; + } else { + this.buf += c; + } + break; + case State.PERCENT: + if (c === "%") { + this.buf += c; + this.state = State.PASSTHROUGH; + } else { + this.handleFormat(); + } + break; + default: + throw new Error( + `State ${this.state} should be unreachable, please file a bug report against Deno at https://github.com/denoland/std/issues`, + ); + } + } + // check for unhandled args + let extras = false; + let err = "%!(EXTRA"; + for (let i = 0; i !== this.haveSeen.length; ++i) { + if (!this.haveSeen[i]) { + extras = true; + err += ` '${Deno.inspect(this.args[i])}'`; + } + } + err += ")"; + if (extras) { + this.buf += err; + } + return this.buf; + } + + // %[]... + handleFormat() { + this.flags = new Flags(); + const flags = this.flags; + for (; this.i < this.format.length; ++this.i) { + const c = this.format[this.i]!; + switch (this.state) { + case State.PERCENT: + switch (c) { + case "[": + this.handlePositional(); + this.state = State.POSITIONAL; + break; + case "+": + flags.plus = true; + break; + case "<": + flags.lessthan = true; + break; + case "-": + flags.dash = true; + flags.zero = false; // only left pad zeros, dash takes precedence + break; + case "#": + flags.sharp = true; + break; + case " ": + flags.space = true; + break; + case "0": + // only left pad zeros, dash takes precedence + flags.zero = !flags.dash; + break; + default: + if (("1" <= c && c <= "9") || c === "." || c === "*") { + if (c === ".") { + this.flags.precision = 0; + this.state = State.PRECISION; + this.i++; + } else { + this.state = State.WIDTH; + } + this.handleWidthAndPrecision(flags); + } else { + this.handleVerb(); + return; // always end in verb + } + } // switch c + break; + case State.POSITIONAL: + // TODO(bartlomieju): either a verb or * only verb for now + if (c === "*") { + const worp = this.flags.precision === -1 + ? WorP.WIDTH + : WorP.PRECISION; + this.handleWidthOrPrecisionRef(worp); + this.state = State.PERCENT; + break; + } else { + this.handleVerb(); + return; // always end in verb + } + default: + throw new Error( + `State ${this.state} should be unreachable, please file a bug report against Deno at https://github.com/denoland/std/issues`, + ); + } // switch state + } + } + + /** + * Handle width or precision + * @param wOrP + */ + handleWidthOrPrecisionRef(wOrP: WorP) { + if (this.argNum >= this.args.length) { + // handle Positional should have already taken care of it... + return; + } + const arg = this.args[this.argNum]; + this.haveSeen[this.argNum] = true; + if (typeof arg === "number") { + switch (wOrP) { + case WorP.WIDTH: + this.flags.width = arg; + break; + default: + this.flags.precision = arg; + } + } else { + const tmp = wOrP === WorP.WIDTH ? "WIDTH" : "PREC"; + this.tmpError = `%!(BAD ${tmp} '${this.args[this.argNum]}')`; + } + this.argNum++; + } + + /** + * Handle width and precision + * @param flags + */ + handleWidthAndPrecision(flags: Flags) { + const fmt = this.format; + for (; this.i !== this.format.length; ++this.i) { + const c = fmt[this.i]!; + switch (this.state) { + case State.WIDTH: + switch (c) { + case ".": + // initialize precision, %9.f -> precision=0 + this.flags.precision = 0; + this.state = State.PRECISION; + break; + case "*": + this.handleWidthOrPrecisionRef(WorP.WIDTH); + // force . or flag at this point + break; + default: { + const val = parseInt(c); + // most likely parseInt does something stupid that makes + // it unusable for this scenario ... + // if we encounter a non (number|*|.) we're done with prec & wid + if (isNaN(val)) { + this.i--; + this.state = State.PERCENT; + return; + } + flags.width = flags.width === -1 ? 0 : flags.width; + flags.width *= 10; + flags.width += val; + } + } // switch c + break; + case State.PRECISION: { + if (c === "*") { + this.handleWidthOrPrecisionRef(WorP.PRECISION); + break; + } + const val = parseInt(c); + if (isNaN(val)) { + // one too far, rewind + this.i--; + this.state = State.PERCENT; + return; + } + flags.precision *= 10; + flags.precision += val; + break; + } + default: + throw new Error( + `State ${this.state} should be unreachable, please file a bug report against Deno at https://github.com/denoland/std/issues`, + ); + } // switch state + } + } + + /** Handle positional */ + handlePositional() { + if (this.format[this.i] !== "[") { + // sanity only + throw new Error( + "Should be unreachable, please file a bug report against Deno at https://github.com/denoland/std/issues", + ); + } + let positional = 0; + const format = this.format; + this.i++; + let err = false; + for (; this.i !== this.format.length; ++this.i) { + if (format[this.i] === "]") { + break; + } + positional *= 10; + const val = parseInt(format[this.i]!, 10); + if (isNaN(val)) { + //throw new Error( + // `invalid character in positional: ${format}[${format[this.i]}]` + //); + this.tmpError = "%!(BAD INDEX)"; + err = true; + } + positional += val; + } + if (positional - 1 >= this.args.length) { + this.tmpError = "%!(BAD INDEX)"; + err = true; + } + this.argNum = err ? this.argNum : positional - 1; + } + + /** Handle less than */ + handleLessThan(): string { + // deno-lint-ignore no-explicit-any + const arg = this.args[this.argNum] as any; + if ((arg || {}).constructor.name !== "Array") { + throw new Error( + `Cannot handle less than '<' flag: 'arg' is not an array`, + ); + } + let str = "[ "; + for (let i = 0; i !== arg.length; ++i) { + if (i !== 0) str += ", "; + str += this._handleVerb(arg[i]); + } + return str + " ]"; + } + + /** Handle verb */ + handleVerb() { + const verb = this.format[this.i]; + this.verb = verb || this.verb; + if (this.tmpError) { + this.buf += this.tmpError; + this.tmpError = undefined; + if (this.argNum < this.haveSeen.length) { + this.haveSeen[this.argNum] = true; // keep track of used args + } + } else if (this.args.length <= this.argNum) { + this.buf += `%!(MISSING '${verb}')`; + } else { + const arg = this.args[this.argNum]; // check out of range + this.haveSeen[this.argNum] = true; // keep track of used args + if (this.flags.lessthan) { + this.buf += this.handleLessThan(); + } else { + this.buf += this._handleVerb(arg); + } + } + this.argNum++; // if there is a further positional, it will reset. + this.state = State.PASSTHROUGH; + } + + // deno-lint-ignore no-explicit-any + _handleVerb(arg: any): string { + switch (this.verb) { + case "t": + return this.pad(arg.toString()); + case "b": + return this.fmtNumber(arg as number, 2); + case "c": + return this.fmtNumberCodePoint(arg as number); + case "d": + return this.fmtNumber(arg as number, 10); + case "o": + return this.fmtNumber(arg as number, 8); + case "x": + return this.fmtHex(arg); + case "X": + return this.fmtHex(arg, true); + case "e": + return this.fmtFloatE(arg as number); + case "E": + return this.fmtFloatE(arg as number, true); + case "f": + case "F": + return this.fmtFloatF(arg as number); + case "g": + return this.fmtFloatG(arg as number); + case "G": + return this.fmtFloatG(arg as number, true); + case "s": + return this.fmtString(arg as string); + case "T": + return this.fmtString(typeof arg); + case "v": + return this.fmtV(arg); + case "j": + return this.fmtJ(arg); + case "i": + return this.fmtI(arg, false); + case "I": + return this.fmtI(arg, true); + default: + return `%!(BAD VERB '${this.verb}')`; + } + } + + /** + * Pad a string + * @param s text to pad + */ + pad(s: string): string { + const padding = this.flags.zero ? "0" : " "; + + if (this.flags.dash) { + return s.padEnd(this.flags.width, padding); + } + + return s.padStart(this.flags.width, padding); + } + + /** + * Pad a number + * @param nStr + * @param neg + */ + padNum(nStr: string, neg: boolean): string { + let sign: string; + if (neg) { + sign = "-"; + } else if (this.flags.plus || this.flags.space) { + sign = this.flags.plus ? "+" : " "; + } else { + sign = ""; + } + const zero = this.flags.zero; + if (!zero) { + // sign comes in front of padding when padding w/ zero, + // in from of value if padding with spaces. + nStr = sign + nStr; + } + + const pad = zero ? "0" : " "; + const len = zero ? this.flags.width - sign.length : this.flags.width; + + if (this.flags.dash) { + nStr = nStr.padEnd(len, pad); + } else { + nStr = nStr.padStart(len, pad); + } + + if (zero) { + // see above + nStr = sign + nStr; + } + return nStr; + } + + /** + * Format a number + * @param n + * @param radix + * @param upcase + */ + fmtNumber(n: number, radix: number, upcase = false): string { + let num = Math.abs(n).toString(radix); + const prec = this.flags.precision; + if (prec !== -1) { + this.flags.zero = false; + num = n === 0 && prec === 0 ? "" : num; + while (num.length < prec) { + num = "0" + num; + } + } + let prefix = ""; + if (this.flags.sharp) { + switch (radix) { + case 2: + prefix += "0b"; + break; + case 8: + // don't annotate octal 0 with 0... + prefix += num.startsWith("0") ? "" : "0"; + break; + case 16: + prefix += "0x"; + break; + default: + throw new Error( + `Cannot handle the radix ${radix}: only 2, 8, 16 are supported`, + ); + } + } + // don't add prefix in front of value truncated by precision=0, val=0 + num = num.length === 0 ? num : prefix + num; + if (upcase) { + num = num.toUpperCase(); + } + return this.padNum(num, n < 0); + } + + /** + * Format number with code points + * @param n + */ + fmtNumberCodePoint(n: number): string { + let s = ""; + try { + s = String.fromCodePoint(n); + } catch { + s = UNICODE_REPLACEMENT_CHARACTER; + } + return this.pad(s); + } + + /** + * Format special float + * @param n + */ + fmtFloatSpecial(n: number): string { + // formatting of NaN and Inf are pants-on-head + // stupid and more or less arbitrary. + + if (isNaN(n)) { + this.flags.zero = false; + return this.padNum("NaN", false); + } + if (n === Number.POSITIVE_INFINITY) { + this.flags.zero = false; + this.flags.plus = true; + return this.padNum("Inf", false); + } + if (n === Number.NEGATIVE_INFINITY) { + this.flags.zero = false; + return this.padNum("Inf", true); + } + return ""; + } + + /** + * Round fraction to precision + * @param fractional + * @param precision + * @returns tuple of fractional and round + */ + roundFractionToPrecision( + fractional: string, + precision: number, + ): [string, boolean] { + let round = false; + if (fractional.length > precision) { + fractional = "1" + fractional; // prepend a 1 in case of leading 0 + let tmp = parseInt(fractional.slice(0, precision + 2)) / 10; + tmp = Math.round(tmp); + fractional = Math.floor(tmp).toString(); + round = fractional[0] === "2"; + fractional = fractional.slice(1); // remove extra 1 + } else { + while (fractional.length < precision) { + fractional += "0"; + } + } + return [fractional, round]; + } + + /** + * Format float E + * @param n + * @param upcase + */ + fmtFloatE(n: number, upcase = false): string { + const special = this.fmtFloatSpecial(n); + if (special !== "") { + return special; + } + + const m = n.toExponential().match(FLOAT_REGEXP); + if (!m) { + throw new Error( + "Should be unreachable, please file a bug report against Deno at https://github.com/denoland/std/issues", + ); + } + const precision = this.flags.precision !== -1 + ? this.flags.precision + : DEFAULT_PRECISION; + const [fractional, rounding] = this.roundFractionToPrecision( + m[F.fractional] ?? "", + precision, + ); + + let e = m[F.exponent]!; + let esign = m[F.esign]!; + // scientific notation output with exponent padded to minlen 2 + let mantissa = parseInt(m[F.mantissa]!); + if (rounding) { + mantissa += 1; + if (10 <= mantissa) { + mantissa = 1; + const r = parseInt(esign + e) + 1; + e = Math.abs(r).toString(); + esign = r < 0 ? "-" : "+"; + } + } + e = e.length === 1 ? "0" + e : e; + const val = `${mantissa}.${fractional}${upcase ? "E" : "e"}${esign}${e}`; + return this.padNum(val, n < 0); + } + + /** + * Format float F + * @param n + */ + fmtFloatF(n: number): string { + const special = this.fmtFloatSpecial(n); + if (special !== "") { + return special; + } + + // stupid helper that turns a number into a (potentially) + // VERY long string. + function expandNumber(n: number): string { + if (Number.isSafeInteger(n)) { + return n.toString() + "."; + } + + const t = n.toExponential().split("e"); + let m = t[0]!.replace(".", ""); + const e = parseInt(t[1]!); + if (e < 0) { + let nStr = "0."; + for (let i = 0; i !== Math.abs(e) - 1; ++i) { + nStr += "0"; + } + return (nStr += m); + } else { + const splIdx = e + 1; + while (m.length < splIdx) { + m += "0"; + } + return m.slice(0, splIdx) + "." + m.slice(splIdx); + } + } + // avoiding sign makes padding easier + const val = expandNumber(Math.abs(n)) as string; + let [dig, fractional] = val.split(".") as [string, string]; + + const precision = this.flags.precision !== -1 + ? this.flags.precision + : DEFAULT_PRECISION; + let round = false; + [fractional, round] = this.roundFractionToPrecision(fractional, precision); + if (round) { + dig = (parseInt(dig) + 1).toString(); + } + return this.padNum(`${dig}.${fractional}`, n < 0); + } + + /** + * Format float G + * @param n + * @param upcase + */ + fmtFloatG(n: number, upcase = false): string { + const special = this.fmtFloatSpecial(n); + if (special !== "") { + return special; + } + + // The double argument representing a floating-point number shall be + // converted in the style f or e (or in the style F or E in + // the case of a G conversion specifier), depending on the + // value converted and the precision. Let P equal the + // precision if non-zero, 6 if the precision is omitted, or 1 + // if the precision is zero. Then, if a conversion with style E would + // have an exponent of X: + + // - If P > X>=-4, the conversion shall be with style f (or F ) + // and precision P -( X+1). + + // - Otherwise, the conversion shall be with style e (or E ) + // and precision P -1. + + // Finally, unless the '#' flag is used, any trailing zeros shall be + // removed from the fractional portion of the result and the + // decimal-point character shall be removed if there is no + // fractional portion remaining. + + // A double argument representing an infinity or NaN shall be + // converted in the style of an f or F conversion specifier. + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html + + let P = this.flags.precision !== -1 + ? this.flags.precision + : DEFAULT_PRECISION; + P = P === 0 ? 1 : P; + + const m = n.toExponential().match(FLOAT_REGEXP); + if (!m) { + throw new Error( + "Should be unreachable, please file a bug report against Deno at https://github.com/denoland/std/issues", + ); + } + + const X = parseInt(m[F.exponent]!) * (m[F.esign] === "-" ? -1 : 1); + let nStr = ""; + if (P > X && X >= -4) { + this.flags.precision = P - (X + 1); + nStr = this.fmtFloatF(n); + if (!this.flags.sharp) { + nStr = nStr.replace(/\.?0*$/, ""); + } + } else { + this.flags.precision = P - 1; + nStr = this.fmtFloatE(n); + if (!this.flags.sharp) { + nStr = nStr.replace(/\.?0*e/, upcase ? "E" : "e"); + } + } + return nStr; + } + + /** + * Format string + * @param s + */ + fmtString(s: string): string { + if (this.flags.precision !== -1) { + s = s.slice(0, this.flags.precision); + } + return this.pad(s); + } + + /** + * Format hex + * @param val + * @param upper + */ + fmtHex(val: string | number, upper = false): string { + // allow others types ? + switch (typeof val) { + case "number": + return this.fmtNumber(val as number, 16, upper); + case "string": { + const sharp = this.flags.sharp && val.length !== 0; + let hex = sharp ? "0x" : ""; + const prec = this.flags.precision; + const end = prec !== -1 ? min(prec, val.length) : val.length; + for (let i = 0; i !== end; ++i) { + if (i !== 0 && this.flags.space) { + hex += sharp ? " 0x" : " "; + } + // TODO(bartlomieju): for now only taking into account the + // lower half of the codePoint, ie. as if a string + // is a list of 8bit values instead of UCS2 runes + const c = (val.charCodeAt(i) & 0xff).toString(16); + hex += c.length === 1 ? `0${c}` : c; + } + if (upper) { + hex = hex.toUpperCase(); + } + return this.pad(hex); + } + default: + throw new Error( + `Cannot format hex, only number and string are supported for hex formatting: ${typeof val} is given`, + ); + } + } + + /** + * Format value + * @param val + */ + fmtV(val: Record): string { + if (this.flags.sharp) { + const options = this.flags.precision !== -1 + ? { depth: this.flags.precision } + : {}; + return this.pad(Deno.inspect(val, options)); + } else { + const p = this.flags.precision; + return p === -1 ? val.toString() : val.toString().slice(0, p); + } + } + + /** + * Format JSON + * @param val + */ + fmtJ(val: unknown): string { + return JSON.stringify(val); + } + + /** + * Format inspect + * @param val + * @param compact Whether or not the output should be compact. + */ + fmtI(val: unknown, compact: boolean): string { + return Deno.inspect(val, { + colors: !Deno?.noColor, + compact, + depth: Infinity, + iterableLimit: Infinity, + }); + } +} + +/** + * Converts and formats a variable number of `args` as is specified by `format`. + * `sprintf` returns the formatted string. + * + * See the module documentation for the available format strings. + * + * @example Usage + * ```ts + * import { sprintf } from "@std/fmt/printf"; + * import { assertEquals } from "@std/assert"; + * + * assertEquals(sprintf("%d", 9), "9"); + * + * assertEquals(sprintf("%o", 9), "11"); + * + * assertEquals(sprintf("%f", 4), "4.000000"); + * + * assertEquals(sprintf("%.3f", 0.9999), "1.000"); + * ``` + * + * @param format The format string to use + * @param args The arguments to format + * @returns The formatted string + */ +export function sprintf(format: string, ...args: unknown[]): string { + const printf = new Printf(format, ...args); + return printf.doPrintf(); +} + +/** + * Converts and format a variable number of `args` as is specified by `format`. + * `printf` writes the formatted string to standard output. + * + * See the module documentation for the available format strings. + * + * @example Usage + * ```ts no-assert + * import { printf } from "@std/fmt/printf"; + * + * printf("%d", 9); // Prints "9" + * + * printf("%o", 9); // Prints "11" + * + * printf("%f", 4); // Prints "4.000000" + * + * printf("%.3f", 0.9999); // Prints "1.000" + * ``` + * + * @param format The format string to use + * @param args The arguments to format + */ +export function printf(format: string, ...args: unknown[]) { + const s = sprintf(format, ...args); + Deno.stdout.writeSync(new TextEncoder().encode(s)); +} diff --git a/vendor/jsr.io/@std/fmt/1.0.3_meta.json b/vendor/jsr.io/@std/fmt/1.0.3_meta.json new file mode 100644 index 0000000..1f36000 --- /dev/null +++ b/vendor/jsr.io/@std/fmt/1.0.3_meta.json @@ -0,0 +1,60 @@ +{ + "manifest": { + "/LICENSE": { + "size": 1075, + "checksum": "sha256-0961f97da6619d5fe9ddb98649191d5ca6e958856ea5252f4cce7c9b85513819" + }, + "/printf.ts": { + "size": 29850, + "checksum": "sha256-2fb4be8843f7bd00a2d4c77552ca7f2e3efd5d0091c739c669abc4d82a93cae8" + }, + "/bytes.ts": { + "size": 5651, + "checksum": "sha256-883ff416b545ee8fb3388e4f18dcd4ddc5b5138fffba777e786144a080695d73" + }, + "/deno.json": { + "size": 192, + "checksum": "sha256-410672a43b0d631a3e766a627c3b8e557a6288e905f14b5859f2a9369e262d9b" + }, + "/printf_test.ts": { + "size": 27158, + "checksum": "sha256-83b8447d270ad5a015510cb5eedc6a0f5e27704766575ceecb0bb8cb58c1cb23" + }, + "/bytes_test.ts": { + "size": 8640, + "checksum": "sha256-f44ec04f6d2368813e5a746adcd060dd41c5a2721b1b873e577d1cd1b82aaa8b" + }, + "/duration_test.ts": { + "size": 1999, + "checksum": "sha256-4bd1a8c231a698af2a2cd3888b67e6abf9ea0bc062876d4c127cd32c4a99cc56" + }, + "/duration.ts": { + "size": 4599, + "checksum": "sha256-f77d8641e2500d733861f27252b11ffddccaa8b8a65ab39603134793c3a579c0" + }, + "/README.md": { + "size": 464, + "checksum": "sha256-df54055e214802f0089f6d71ca85c66b898a5fa2bc69fa7c4683503dcd8cc3f8" + }, + "/colors.ts": { + "size": 21831, + "checksum": "sha256-17695d6f9e097eb5c42ebaa06112e2004e992af3bc3ade9a579fafd9556e6128" + }, + "/colors_test.ts": { + "size": 6418, + "checksum": "sha256-b3802d6d263310ae10d19292583ad7e36065d52a131e77c854ff519a6c1f4360" + } + }, + "moduleGraph2": { + "/bytes.ts": {}, + "/printf.ts": {}, + "/duration.ts": {}, + "/colors.ts": {} + }, + "exports": { + "./bytes": "./bytes.ts", + "./colors": "./colors.ts", + "./duration": "./duration.ts", + "./printf": "./printf.ts" + } +} \ No newline at end of file diff --git a/vendor/jsr.io/@std/fmt/meta.json b/vendor/jsr.io/@std/fmt/meta.json new file mode 100644 index 0000000..74bb3e2 --- /dev/null +++ b/vendor/jsr.io/@std/fmt/meta.json @@ -0,0 +1,55 @@ +{ + "scope": "std", + "name": "fmt", + "latest": "1.0.3", + "versions": { + "0.222.1": {}, + "0.225.5": {}, + "0.203.0": {}, + "0.225.6": {}, + "0.218.0": {}, + "1.0.0-rc.1": {}, + "0.206.0": {}, + "1.0.2": {}, + "0.225.3": {}, + "1.0.0": {}, + "0.214.0": {}, + "0.219.0": {}, + "0.222.0": {}, + "0.204.0": {}, + "0.218.1": {}, + "0.223.0": {}, + "0.218.2": {}, + "0.213.0": {}, + "0.209.0": {}, + "0.210.0": {}, + "0.217.0": {}, + "0.201.0": {}, + "0.205.0": {}, + "0.212.0": {}, + "0.197.0": {}, + "0.211.0": {}, + "0.224.0": {}, + "0.208.0": {}, + "0.216.0": {}, + "0.202.0": {}, + "0.225.4": {}, + "1.0.3": {}, + "0.225.2": {}, + "0.221.0": {}, + "1.0.1": {}, + "0.213.1": {}, + "0.225.0": { + "yanked": true + }, + "0.215.0": {}, + "0.225.1": {}, + "0.219.1": {}, + "0.200.0": {}, + "0.207.0": {}, + "0.220.1": {}, + "0.199.0": {}, + "0.196.0": {}, + "0.198.0": {} + } +} \ No newline at end of file