diff options
Diffstat (limited to 'std/fmt')
-rw-r--r-- | std/fmt/README.md | 240 | ||||
-rw-r--r-- | std/fmt/TODO | 13 | ||||
-rw-r--r-- | std/fmt/colors.ts | 522 | ||||
-rw-r--r-- | std/fmt/colors_test.ts | 230 | ||||
-rw-r--r-- | std/fmt/printf.ts | 757 | ||||
-rw-r--r-- | std/fmt/printf_test.ts | 674 |
6 files changed, 0 insertions, 2436 deletions
diff --git a/std/fmt/README.md b/std/fmt/README.md deleted file mode 100644 index 8c44d78a7..000000000 --- a/std/fmt/README.md +++ /dev/null @@ -1,240 +0,0 @@ -# Printf for Deno - -This is very much a work-in-progress. I'm actively soliciting feedback. What -immediately follows are points for discussion. - -If you are looking for the documentation proper, skip to: - - "printf: prints formatted output" - -and - - "Colors" - -below. - -## Discussion - -This is very much a work-in-progress. I'm actively soliciting feedback. - -- What useful features are available in other languages apart from Golang and C? - -- behaviour of `%v` verb. In Golang, this is a shortcut verb to "print the - default format" of the argument. It is currently implemented to format using - `toString` in the default case and `inspect` if the `%#v` alternative format - flag is used in the format directive. Alternatively, `%V` could be used to - distinguish the two. - - `inspect` output is not defined, however. This may be problematic if using - this code on other platforms (and expecting interoperability). To my - knowledge, no suitable specification of object representation aside from JSON - and `toString` exist. ( Aside: see "[Common object formats][3]" in the - "Console Living Standard" which basically says "do whatever" ) - -- `%j` verb. This is an extension particular to this implementation. Currently - not very sophisticated, it just runs `JSON.stringify` on the argument. - Consider possible modifier flags, etc. - -- `<` verb. This is an extension that assumes the argument is an array and will - format each element according to the format (surrounded by [] and separated by - comma) (`<` Mnemonic: pull each element out of array) - -- how to deal with more newfangled JavaScript features (generic Iterables, Map - and Set types, typed Arrays, ...) - -- the implementation is fairly rough around the edges: - -- currently contains little in the way of checking for correctness. Conceivably, - there will be a 'strict' form, e.g. that ensures only Number-ish arguments are - passed to %f flags. - -- assembles output using string concatenation instead of utilizing buffers or - other optimizations. It would be nice to have printf / sprintf / fprintf (etc) - all in one. - -- float formatting is handled by toString() and to `toExponential` along with a - mess of Regexp. Would be nice to use fancy match. - -- some flags that are potentially applicable ( POSIX long and unsigned modifiers - are not likely useful) are missing, namely %q (print quoted), %U (unicode - format) - -# printf: prints formatted output - -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: - - %<verb> - -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` | - -## 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 9, 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` | ues 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')" - -# Colors - -Adds functions used for displaying colored text. - -## Usage - -```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, -})); -``` - -[1]: https://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html -[2]: https://golang.org/pkg/fmt/ -[3]: https://console.spec.whatwg.org/#object-formats diff --git a/std/fmt/TODO b/std/fmt/TODO deleted file mode 100644 index 7f95c7a78..000000000 --- a/std/fmt/TODO +++ /dev/null @@ -1,13 +0,0 @@ - -* "native" formatting, json, arrays, object/structs, functions ... -* %q %U -* Java has a %n flag to print the platform native newline... in POSIX - that means "number of chars printed so far", though. -* Use of Writer and Buffer internally in order to make fprintf, printf, etc. - easier and more elegant. - -* See "Discussion" in README - -* scanf, pack, unpack, annotated hex -* Consistent error handling. -* Rewrite (probably), now that I know how it's done. diff --git a/std/fmt/colors.ts b/std/fmt/colors.ts deleted file mode 100644 index 3596638f5..000000000 --- a/std/fmt/colors.ts +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// A module to print ANSI terminal colors. Inspired by chalk, kleur, and colors -// on npm. -// -// ``` -// import { bgBlue, red, bold } from "https://deno.land/std/fmt/colors.ts"; -// console.log(bgBlue(red(bold("Hello world!")))); -// ``` -// -// This module supports `NO_COLOR` environmental variable disabling any coloring -// if `NO_COLOR` is set. -// -// This module is browser compatible. - -const noColor = globalThis.Deno?.noColor ?? 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): void { - 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: - * - * rgba24("foo", 0xff00ff); - * rgba24("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: - * - * bgRgba24("foo", 0xff00ff); - * bgRgba24("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/2b56fb0c7a07108e5b54241e8faec160d393aedb/index.js -const ANSI_PATTERN = new RegExp( - [ - "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", - "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))", - ].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/std/fmt/colors_test.ts b/std/fmt/colors_test.ts deleted file mode 100644 index 7f5940a4d..000000000 --- a/std/fmt/colors_test.ts +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "../testing/asserts.ts"; -import * as c from "./colors.ts"; -import "../examples/colors.ts"; - -Deno.test("singleColor", function (): void { - assertEquals(c.red("foo bar"), "[31mfoo bar[39m"); -}); - -Deno.test("doubleColor", function (): void { - assertEquals(c.bgBlue(c.red("foo bar")), "[44m[31mfoo bar[39m[49m"); -}); - -Deno.test("replacesCloseCharacters", function (): void { - assertEquals(c.red("Hel[39mlo"), "[31mHel[31mlo[39m"); -}); - -Deno.test("enablingColors", function (): void { - assertEquals(c.getColorEnabled(), true); - c.setColorEnabled(false); - assertEquals(c.bgBlue(c.red("foo bar")), "foo bar"); - c.setColorEnabled(true); - assertEquals(c.red("foo bar"), "[31mfoo bar[39m"); -}); - -Deno.test("testBold", function (): void { - assertEquals(c.bold("foo bar"), "[1mfoo bar[22m"); -}); - -Deno.test("testDim", function (): void { - assertEquals(c.dim("foo bar"), "[2mfoo bar[22m"); -}); - -Deno.test("testItalic", function (): void { - assertEquals(c.italic("foo bar"), "[3mfoo bar[23m"); -}); - -Deno.test("testUnderline", function (): void { - assertEquals(c.underline("foo bar"), "[4mfoo bar[24m"); -}); - -Deno.test("testInverse", function (): void { - assertEquals(c.inverse("foo bar"), "[7mfoo bar[27m"); -}); - -Deno.test("testHidden", function (): void { - assertEquals(c.hidden("foo bar"), "[8mfoo bar[28m"); -}); - -Deno.test("testStrikethrough", function (): void { - assertEquals(c.strikethrough("foo bar"), "[9mfoo bar[29m"); -}); - -Deno.test("testBlack", function (): void { - assertEquals(c.black("foo bar"), "[30mfoo bar[39m"); -}); - -Deno.test("testRed", function (): void { - assertEquals(c.red("foo bar"), "[31mfoo bar[39m"); -}); - -Deno.test("testGreen", function (): void { - assertEquals(c.green("foo bar"), "[32mfoo bar[39m"); -}); - -Deno.test("testYellow", function (): void { - assertEquals(c.yellow("foo bar"), "[33mfoo bar[39m"); -}); - -Deno.test("testBlue", function (): void { - assertEquals(c.blue("foo bar"), "[34mfoo bar[39m"); -}); - -Deno.test("testMagenta", function (): void { - assertEquals(c.magenta("foo bar"), "[35mfoo bar[39m"); -}); - -Deno.test("testCyan", function (): void { - assertEquals(c.cyan("foo bar"), "[36mfoo bar[39m"); -}); - -Deno.test("testWhite", function (): void { - assertEquals(c.white("foo bar"), "[37mfoo bar[39m"); -}); - -Deno.test("testGray", function (): void { - assertEquals(c.gray("foo bar"), "[90mfoo bar[39m"); -}); - -Deno.test("testBrightBlack", function (): void { - assertEquals(c.brightBlack("foo bar"), "[90mfoo bar[39m"); -}); - -Deno.test("testBrightRed", function (): void { - assertEquals(c.brightRed("foo bar"), "[91mfoo bar[39m"); -}); - -Deno.test("testBrightGreen", function (): void { - assertEquals(c.brightGreen("foo bar"), "[92mfoo bar[39m"); -}); - -Deno.test("testBrightYellow", function (): void { - assertEquals(c.brightYellow("foo bar"), "[93mfoo bar[39m"); -}); - -Deno.test("testBrightBlue", function (): void { - assertEquals(c.brightBlue("foo bar"), "[94mfoo bar[39m"); -}); - -Deno.test("testBrightMagenta", function (): void { - assertEquals(c.brightMagenta("foo bar"), "[95mfoo bar[39m"); -}); - -Deno.test("testBrightCyan", function (): void { - assertEquals(c.brightCyan("foo bar"), "[96mfoo bar[39m"); -}); - -Deno.test("testBrightWhite", function (): void { - assertEquals(c.brightWhite("foo bar"), "[97mfoo bar[39m"); -}); - -Deno.test("testBgBlack", function (): void { - assertEquals(c.bgBlack("foo bar"), "[40mfoo bar[49m"); -}); - -Deno.test("testBgRed", function (): void { - assertEquals(c.bgRed("foo bar"), "[41mfoo bar[49m"); -}); - -Deno.test("testBgGreen", function (): void { - assertEquals(c.bgGreen("foo bar"), "[42mfoo bar[49m"); -}); - -Deno.test("testBgYellow", function (): void { - assertEquals(c.bgYellow("foo bar"), "[43mfoo bar[49m"); -}); - -Deno.test("testBgBlue", function (): void { - assertEquals(c.bgBlue("foo bar"), "[44mfoo bar[49m"); -}); - -Deno.test("testBgMagenta", function (): void { - assertEquals(c.bgMagenta("foo bar"), "[45mfoo bar[49m"); -}); - -Deno.test("testBgCyan", function (): void { - assertEquals(c.bgCyan("foo bar"), "[46mfoo bar[49m"); -}); - -Deno.test("testBgWhite", function (): void { - assertEquals(c.bgWhite("foo bar"), "[47mfoo bar[49m"); -}); - -Deno.test("testBgBrightBlack", function (): void { - assertEquals(c.bgBrightBlack("foo bar"), "[100mfoo bar[49m"); -}); - -Deno.test("testBgBrightRed", function (): void { - assertEquals(c.bgBrightRed("foo bar"), "[101mfoo bar[49m"); -}); - -Deno.test("testBgBrightGreen", function (): void { - assertEquals(c.bgBrightGreen("foo bar"), "[102mfoo bar[49m"); -}); - -Deno.test("testBgBrightYellow", function (): void { - assertEquals(c.bgBrightYellow("foo bar"), "[103mfoo bar[49m"); -}); - -Deno.test("testBgBrightBlue", function (): void { - assertEquals(c.bgBrightBlue("foo bar"), "[104mfoo bar[49m"); -}); - -Deno.test("testBgBrightMagenta", function (): void { - assertEquals(c.bgBrightMagenta("foo bar"), "[105mfoo bar[49m"); -}); - -Deno.test("testBgBrightCyan", function (): void { - assertEquals(c.bgBrightCyan("foo bar"), "[106mfoo bar[49m"); -}); - -Deno.test("testBgBrightWhite", function (): void { - assertEquals(c.bgBrightWhite("foo bar"), "[107mfoo bar[49m"); -}); - -Deno.test("testClampUsingRgb8", function (): void { - assertEquals(c.rgb8("foo bar", -10), "[38;5;0mfoo bar[39m"); -}); - -Deno.test("testTruncateUsingRgb8", function (): void { - assertEquals(c.rgb8("foo bar", 42.5), "[38;5;42mfoo bar[39m"); -}); - -Deno.test("testRgb8", function (): void { - assertEquals(c.rgb8("foo bar", 42), "[38;5;42mfoo bar[39m"); -}); - -Deno.test("test_bgRgb8", function (): void { - assertEquals(c.bgRgb8("foo bar", 42), "[48;5;42mfoo bar[49m"); -}); - -Deno.test("test_rgb24", function (): void { - assertEquals( - c.rgb24("foo bar", { - r: 41, - g: 42, - b: 43, - }), - "[38;2;41;42;43mfoo bar[39m", - ); -}); - -Deno.test("test_rgb24number", function (): void { - assertEquals(c.rgb24("foo bar", 0x070809), "[38;2;7;8;9mfoo bar[39m"); -}); - -Deno.test("test_bgRgb24", function (): void { - assertEquals( - c.bgRgb24("foo bar", { - r: 41, - g: 42, - b: 43, - }), - "[48;2;41;42;43mfoo bar[49m", - ); -}); - -Deno.test("test_bgRgb24number", function (): void { - assertEquals(c.bgRgb24("foo bar", 0x070809), "[48;2;7;8;9mfoo bar[49m"); -}); diff --git a/std/fmt/printf.ts b/std/fmt/printf.ts deleted file mode 100644 index 6a821f208..000000000 --- a/std/fmt/printf.ts +++ /dev/null @@ -1,757 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -/** - * This implementation is inspired by POSIX and Golang but does not port - * implementation code. */ - -enum State { - PASSTHROUGH, - PERCENT, - POSITIONAL, - PRECISION, - WIDTH, -} - -enum WorP { - WIDTH, - PRECISION, -} - -class Flags { - plus?: boolean; - dash?: boolean; - sharp?: boolean; - space?: boolean; - zero?: boolean; - lessthan?: boolean; - width = -1; - precision = -1; -} - -const min = Math.min; -const UNICODE_REPLACEMENT_CHARACTER = "\ufffd"; -const DEFAULT_PRECISION = 6; -const FLOAT_REGEXP = /(-?)(\d)\.?(\d*)e([+-])(\d+)/; - -enum F { - sign = 1, - mantissa, - fractional, - esign, - exponent, -} - -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; - - constructor(format: string, ...args: unknown[]) { - this.format = format; - this.args = args; - this.haveSeen = new Array(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 Error("Should be unreachable, certainly a bug in the lib."); - } - } - // 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; - } - - // %[<positional>]<flag>...<verb> - handleFormat(): void { - 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(`Should not be here ${this.state}, library bug!`); - } // switch state - } - } - - /** - * Handle width or precision - * @param wOrP - */ - handleWidthOrPrecisionRef(wOrP: WorP): void { - 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): void { - 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("can't be here. bug."); - } // switch state - } - } - - /** Handle positional */ - handlePositional(): void { - if (this.format[this.i] !== "[") { - // sanity only - throw new Error("Can't happen? Bug."); - } - 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]); - 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; - return; - } - - /** 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(`arg ${arg} is not an array. Todo better error handling`); - } - let str = "[ "; - for (let i = 0; i !== arg.length; ++i) { - if (i !== 0) str += ", "; - str += this._handleVerb(arg[i]); - } - return str + " ]"; - } - - /** Handle verb */ - handleVerb(): void { - const verb = this.format[this.i]; - this.verb = 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); - 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 base: " + radix); - } - } - // 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 (RangeError) { - 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 - */ - roundFractionToPrecision(fractional: string, precision: number): string { - if (fractional.length > precision) { - fractional = "1" + fractional; // prepend a 1 in case of leading 0 - let tmp = parseInt(fractional.substr(0, precision + 2)) / 10; - tmp = Math.round(tmp); - fractional = Math.floor(tmp).toString(); - fractional = fractional.substr(1); // remove extra 1 - } else { - while (fractional.length < precision) { - fractional += "0"; - } - } - return fractional; - } - - /** - * 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 Error("can't happen, bug"); - } - - let fractional = m[F.fractional]; - const precision = this.flags.precision !== -1 - ? this.flags.precision - : DEFAULT_PRECISION; - fractional = this.roundFractionToPrecision(fractional, precision); - - let e = m[F.exponent]; - // scientific notation output with exponent padded to minlen 2 - e = e.length == 1 ? "0" + e : e; - - const val = `${m[F.mantissa]}.${fractional}${upcase ? "E" : "e"}${ - m[F.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.substr(0, splIdx) + "." + m.substr(splIdx); - } - } - // avoiding sign makes padding easier - const val = expandNumber(Math.abs(n)) as string; - const arr = val.split("."); - const dig = arr[0]; - let fractional = arr[1]; - - const precision = this.flags.precision !== -1 - ? this.flags.precision - : DEFAULT_PRECISION; - fractional = this.roundFractionToPrecision(fractional, precision); - - 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 Error("can't happen"); - } - - 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.substr(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( - "currently only number and string are implemented for hex", - ); - } - } - - /** - * Format value - * @param val - */ - fmtV(val: Record<string, unknown>): 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().substr(0, p); - } - } - - /** - * Format JSON - * @param val - */ - fmtJ(val: unknown): string { - return JSON.stringify(val); - } -} - -/** - * Converts and format a variable number of `args` as is specified by `format`. - * `sprintf` returns the formatted string. - * - * @param format - * @param args - */ -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. - * @param format - * @param args - */ -export function printf(format: string, ...args: unknown[]): void { - const s = sprintf(format, ...args); - Deno.stdout.writeSync(new TextEncoder().encode(s)); -} diff --git a/std/fmt/printf_test.ts b/std/fmt/printf_test.ts deleted file mode 100644 index f24085848..000000000 --- a/std/fmt/printf_test.ts +++ /dev/null @@ -1,674 +0,0 @@ -// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -// -// A number of test-cases based on: -// -// https://golang.org/src/fmt/fmt_test.go -// BSD: Copyright (c) 2009 The Go Authors. All rights reserved. - -import { sprintf } from "./printf.ts"; -import { assertEquals } from "../testing/asserts.ts"; - -const S = sprintf; - -Deno.test("noVerb", function (): void { - assertEquals(sprintf("bla"), "bla"); -}); - -Deno.test("percent", function (): void { - assertEquals(sprintf("%%"), "%"); - assertEquals(sprintf("!%%!"), "!%!"); - assertEquals(sprintf("!%%"), "!%"); - assertEquals(sprintf("%%!"), "%!"); -}); -Deno.test("testBoolean", function (): void { - assertEquals(sprintf("%t", true), "true"); - assertEquals(sprintf("%10t", true), " true"); - assertEquals(sprintf("%-10t", false), "false "); - assertEquals(sprintf("%t", false), "false"); - assertEquals(sprintf("bla%t", true), "blatrue"); - assertEquals(sprintf("%tbla", false), "falsebla"); -}); - -Deno.test("testIntegerB", function (): void { - assertEquals(S("%b", 4), "100"); - assertEquals(S("%b", -4), "-100"); - assertEquals( - S("%b", 4.1), - "100.0001100110011001100110011001100110011001100110011", - ); - assertEquals( - S("%b", -4.1), - "-100.0001100110011001100110011001100110011001100110011", - ); - assertEquals( - S("%b", Number.MAX_SAFE_INTEGER), - "11111111111111111111111111111111111111111111111111111", - ); - assertEquals( - S("%b", Number.MIN_SAFE_INTEGER), - "-11111111111111111111111111111111111111111111111111111", - ); - // width - - assertEquals(S("%4b", 4), " 100"); -}); - -Deno.test("testIntegerC", function (): void { - assertEquals(S("%c", 0x31), "1"); - assertEquals(S("%c%b", 0x31, 1), "11"); - assertEquals(S("%c", 0x1f4a9), "💩"); - //width - assertEquals(S("%4c", 0x31), " 1"); -}); - -Deno.test("testIntegerD", function (): void { - assertEquals(S("%d", 4), "4"); - assertEquals(S("%d", -4), "-4"); - assertEquals(S("%d", Number.MAX_SAFE_INTEGER), "9007199254740991"); - assertEquals(S("%d", Number.MIN_SAFE_INTEGER), "-9007199254740991"); -}); - -Deno.test("testIntegerO", function (): void { - assertEquals(S("%o", 4), "4"); - assertEquals(S("%o", -4), "-4"); - assertEquals(S("%o", 9), "11"); - assertEquals(S("%o", -9), "-11"); - assertEquals(S("%o", Number.MAX_SAFE_INTEGER), "377777777777777777"); - assertEquals(S("%o", Number.MIN_SAFE_INTEGER), "-377777777777777777"); - // width - assertEquals(S("%4o", 4), " 4"); -}); -Deno.test("testIntegerx", function (): void { - assertEquals(S("%x", 4), "4"); - assertEquals(S("%x", -4), "-4"); - assertEquals(S("%x", 9), "9"); - assertEquals(S("%x", -9), "-9"); - assertEquals(S("%x", Number.MAX_SAFE_INTEGER), "1fffffffffffff"); - assertEquals(S("%x", Number.MIN_SAFE_INTEGER), "-1fffffffffffff"); - // width - assertEquals(S("%4x", -4), " -4"); - assertEquals(S("%-4x", -4), "-4 "); - // plus - assertEquals(S("%+4x", 4), " +4"); - assertEquals(S("%-+4x", 4), "+4 "); -}); -Deno.test("testIntegerX", function (): void { - assertEquals(S("%X", 4), "4"); - assertEquals(S("%X", -4), "-4"); - assertEquals(S("%X", 9), "9"); - assertEquals(S("%X", -9), "-9"); - assertEquals(S("%X", Number.MAX_SAFE_INTEGER), "1FFFFFFFFFFFFF"); - assertEquals(S("%X", Number.MIN_SAFE_INTEGER), "-1FFFFFFFFFFFFF"); -}); - -Deno.test("testFloate", function (): void { - assertEquals(S("%e", 4), "4.000000e+00"); - assertEquals(S("%e", -4), "-4.000000e+00"); - assertEquals(S("%e", 4.1), "4.100000e+00"); - assertEquals(S("%e", -4.1), "-4.100000e+00"); - assertEquals(S("%e", Number.MAX_SAFE_INTEGER), "9.007199e+15"); - assertEquals(S("%e", Number.MIN_SAFE_INTEGER), "-9.007199e+15"); -}); -Deno.test("testFloatE", function (): void { - assertEquals(S("%E", 4), "4.000000E+00"); - assertEquals(S("%E", -4), "-4.000000E+00"); - assertEquals(S("%E", 4.1), "4.100000E+00"); - assertEquals(S("%E", -4.1), "-4.100000E+00"); - assertEquals(S("%E", Number.MAX_SAFE_INTEGER), "9.007199E+15"); - assertEquals(S("%E", Number.MIN_SAFE_INTEGER), "-9.007199E+15"); - assertEquals(S("%E", Number.MIN_VALUE), "5.000000E-324"); - assertEquals(S("%E", Number.MAX_VALUE), "1.797693E+308"); -}); -Deno.test("testFloatfF", function (): void { - assertEquals(S("%f", 4), "4.000000"); - assertEquals(S("%F", 4), "4.000000"); - assertEquals(S("%f", -4), "-4.000000"); - assertEquals(S("%F", -4), "-4.000000"); - assertEquals(S("%f", 4.1), "4.100000"); - assertEquals(S("%F", 4.1), "4.100000"); - assertEquals(S("%f", -4.1), "-4.100000"); - assertEquals(S("%F", -4.1), "-4.100000"); - assertEquals(S("%f", Number.MAX_SAFE_INTEGER), "9007199254740991.000000"); - assertEquals(S("%F", Number.MAX_SAFE_INTEGER), "9007199254740991.000000"); - assertEquals(S("%f", Number.MIN_SAFE_INTEGER), "-9007199254740991.000000"); - assertEquals(S("%F", Number.MIN_SAFE_INTEGER), "-9007199254740991.000000"); - assertEquals(S("%f", Number.MIN_VALUE), "0.000000"); - assertEquals( - S("%.324f", Number.MIN_VALUE), - // eslint-disable-next-line max-len - "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005", - ); - assertEquals(S("%F", Number.MIN_VALUE), "0.000000"); - assertEquals( - S("%f", Number.MAX_VALUE), - // eslint-disable-next-line max-len - "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000", - ); - assertEquals( - S("%F", Number.MAX_VALUE), - // eslint-disable-next-line max-len - "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000", - ); -}); - -Deno.test("testString", function (): void { - assertEquals(S("%s World%s", "Hello", "!"), "Hello World!"); -}); - -Deno.test("testHex", function (): void { - assertEquals(S("%x", "123"), "313233"); - assertEquals(S("%x", "n"), "6e"); -}); -Deno.test("testHeX", function (): void { - assertEquals(S("%X", "123"), "313233"); - assertEquals(S("%X", "n"), "6E"); -}); - -Deno.test("testType", function (): void { - assertEquals(S("%T", new Date()), "object"); - assertEquals(S("%T", 123), "number"); - assertEquals(S("%T", "123"), "string"); - assertEquals(S("%.3T", "123"), "str"); -}); - -Deno.test("testPositional", function (): void { - assertEquals(S("%[1]d%[2]d", 1, 2), "12"); - assertEquals(S("%[2]d%[1]d", 1, 2), "21"); -}); - -Deno.test("testSharp", function (): void { - assertEquals(S("%#x", "123"), "0x313233"); - assertEquals(S("%#X", "123"), "0X313233"); - assertEquals(S("%#x", 123), "0x7b"); - assertEquals(S("%#X", 123), "0X7B"); - assertEquals(S("%#o", 123), "0173"); - assertEquals(S("%#b", 4), "0b100"); -}); - -Deno.test("testWidthAndPrecision", function (): void { - assertEquals( - S("%9.99d", 9), - // eslint-disable-next-line max-len - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009", - ); - assertEquals(S("%1.12d", 9), "000000000009"); - assertEquals(S("%2s", "a"), " a"); - assertEquals(S("%2d", 1), " 1"); - assertEquals(S("%#4x", 1), " 0x1"); - - assertEquals( - S("%*.99d", 9, 9), - // eslint-disable-next-line max-len - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009", - ); - assertEquals( - S("%9.*d", 99, 9), - // eslint-disable-next-line max-len - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009", - ); - assertEquals(S("%*s", 2, "a"), " a"); - assertEquals(S("%*d", 2, 1), " 1"); - assertEquals(S("%#*x", 4, 1), " 0x1"); -}); - -Deno.test("testDash", function (): void { - assertEquals(S("%-2s", "a"), "a "); - assertEquals(S("%-2d", 1), "1 "); -}); -Deno.test("testPlus", function (): void { - assertEquals(S("%-+3d", 1), "+1 "); - assertEquals(S("%+3d", 1), " +1"); - assertEquals(S("%+3d", -1), " -1"); -}); - -Deno.test("testSpace", function (): void { - assertEquals(S("% -3d", 3), " 3 "); -}); - -Deno.test("testZero", function (): void { - assertEquals(S("%04s", "a"), "000a"); -}); - -// relevant test cases from fmt_test.go -// deno-lint-ignore no-explicit-any -const tests: Array<[string, any, string]> = [ - ["%d", 12345, "12345"], - ["%v", 12345, "12345"], - ["%t", true, "true"], - // basic string - ["%s", "abc", "abc"], - // ["%q", "abc", `"abc"`], // TODO: need %q? - ["%x", "abc", "616263"], - ["%x", "\xff\xf0\x0f\xff", "fff00fff"], - ["%X", "\xff\xf0\x0f\xff", "FFF00FFF"], - ["%x", "", ""], - ["% x", "", ""], - ["%#x", "", ""], - ["%# x", "", ""], - ["%x", "xyz", "78797a"], - ["%X", "xyz", "78797A"], - ["% x", "xyz", "78 79 7a"], - ["% X", "xyz", "78 79 7A"], - ["%#x", "xyz", "0x78797a"], - ["%#X", "xyz", "0X78797A"], - ["%# x", "xyz", "0x78 0x79 0x7a"], - ["%# X", "xyz", "0X78 0X79 0X7A"], - // basic bytes : TODO special handling for Buffer? other std types? - // escaped strings : TODO decide whether to have %q - - // characters - ["%c", "x".charCodeAt(0), "x"], - ["%c", 0xe4, "ä"], - ["%c", 0x672c, "本"], - ["%c", "日".charCodeAt(0), "日"], - // Specifying precision should have no effect. - ["%.0c", "⌘".charCodeAt(0), "⌘"], - ["%3c", "⌘".charCodeAt(0), " ⌘"], - ["%-3c", "⌘".charCodeAt(0), "⌘ "], - // Runes that are not printable. - // {"%c", '\U00000e00', "\u0e00"}, - // TODO(bartlomieju) check if \U escape exists in js - //["%c", '\U0010ffff'.codePointAt(0), "\U0010ffff"], - - // Runes that are not valid. - ["%c", -1, "�"], - // TODO(bartomieju): surrogate half, doesn't make sense in itself, how - // to determine in JS? - // ["%c", 0xDC80, "�"], - ["%c", 0x110000, "�"], - ["%c", 0xfffffffff, "�"], - // TODO(bartlomieju): - // escaped characters - // Runes that are not printable. - // Runes that are not valid. - - // width - ["%5s", "abc", " abc"], - ["%2s", "\u263a", " ☺"], - ["%-5s", "abc", "abc "], - ["%05s", "abc", "00abc"], - ["%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"], - ["%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"], - ["%.0s", "日本語日本語", ""], - ["%.5s", "日本語日本語", "日本語日本"], - ["%.10s", "日本語日本語", "日本語日本語"], - // ["%08q", "abc", `000"abc"`], - // TODO(bartlomieju): verb q - // ["%-8q", "abc", `"abc" `], - //["%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`], - ["%.5x", "abcdefghijklmnopqrstuvwxyz", "6162636465"], - //["%.3q", "日本語日本語", `"日本語"`], - //["%.1q", "日本語", `"日"`] - // change of go testcase utf-8([日]) = 0xe697a5, utf-16= 65e5 and - // our %x takes lower byte of string "%.1x", "日本語", "e6"],, - ["%.1x", "日本語", "e5"], - //["%10.1q", "日本語日本語", ` "日"`], - // ["%10v", null, " <nil>"], - // TODO(bartlomieju): null, undefined ... - // ["%-10v", null, "<nil> "], - - // integers - ["%d", 12345, "12345"], - ["%d", -12345, "-12345"], - // ["%d", ^uint8(0), "255"], - //["%d", ^uint16(0), "65535"], - //["%d", ^uint32(0), "4294967295"], - //["%d", ^uint64(0), "18446744073709551615"], - ["%d", -1 << 7, "-128"], - ["%d", -1 << 15, "-32768"], - ["%d", -1 << 31, "-2147483648"], - //["%d", (-1 << 63), "-9223372036854775808"], - ["%.d", 0, ""], - ["%.0d", 0, ""], - ["%6.0d", 0, " "], - ["%06.0d", 0, " "], // 0 flag should be ignored - ["% d", 12345, " 12345"], - ["%+d", 12345, "+12345"], - ["%+d", -12345, "-12345"], - ["%b", 7, "111"], - ["%b", -6, "-110"], - // ["%b", ^uint32(0), "11111111111111111111111111111111"], - // ["%b", ^uint64(0), - // "1111111111111111111111111111111111111111111111111111111111111111"], - // ["%b", int64(-1 << 63), zeroFill("-1", 63, "")], - // 0 octal notation not allowed in struct node... - ["%o", parseInt("01234", 8), "1234"], - ["%#o", parseInt("01234", 8), "01234"], - // ["%o", ^uint32(0), "37777777777"], - // ["%o", ^uint64(0), "1777777777777777777777"], - ["%#X", 0, "0X0"], - ["%x", 0x12abcdef, "12abcdef"], - ["%X", 0x12abcdef, "12ABCDEF"], - // ["%x", ^uint32(0), "ffffffff"], - // ["%X", ^uint64(0), "FFFFFFFFFFFFFFFF"], - ["%.20b", 7, "00000000000000000111"], - ["%10d", 12345, " 12345"], - ["%10d", -12345, " -12345"], - ["%+10d", 12345, " +12345"], - ["%010d", 12345, "0000012345"], - ["%010d", -12345, "-000012345"], - ["%20.8d", 1234, " 00001234"], - ["%20.8d", -1234, " -00001234"], - ["%020.8d", 1234, " 00001234"], - ["%020.8d", -1234, " -00001234"], - ["%-20.8d", 1234, "00001234 "], - ["%-20.8d", -1234, "-00001234 "], - ["%-#20.8x", 0x1234abc, "0x01234abc "], - ["%-#20.8X", 0x1234abc, "0X01234ABC "], - ["%-#20.8o", parseInt("01234", 8), "00001234 "], - // Test correct f.intbuf overflow checks. - // TODO(bartlomieju): lazy - // unicode format - // TODO(bartlomieju): decide whether unicode verb makes sense %U - - // floats - ["%+.3e", 0.0, "+0.000e+00"], - ["%+.3e", 1.0, "+1.000e+00"], - ["%+.3f", -1.0, "-1.000"], - ["%+.3F", -1.0, "-1.000"], - //["%+.3F", float32(-1.0), "-1.000"], - ["%+07.2f", 1.0, "+001.00"], - ["%+07.2f", -1.0, "-001.00"], - ["%-07.2f", 1.0, "1.00 "], - ["%-07.2f", -1.0, "-1.00 "], - ["%+-07.2f", 1.0, "+1.00 "], - ["%+-07.2f", -1.0, "-1.00 "], - ["%-+07.2f", 1.0, "+1.00 "], - ["%-+07.2f", -1.0, "-1.00 "], - ["%+10.2f", +1.0, " +1.00"], - ["%+10.2f", -1.0, " -1.00"], - ["% .3E", -1.0, "-1.000E+00"], - ["% .3e", 1.0, " 1.000e+00"], - ["%+.3g", 0.0, "+0"], - ["%+.3g", 1.0, "+1"], - ["%+.3g", -1.0, "-1"], - ["% .3g", -1.0, "-1"], - ["% .3g", 1.0, " 1"], - // //["%b", float32(1.0), "8388608p-23"], - // ["%b", 1.0, "4503599627370496p-52"], - // // Test sharp flag used with floats. - ["%#g", 1e-323, "1.00000e-323"], - ["%#g", -1.0, "-1.00000"], - ["%#g", 1.1, "1.10000"], - ["%#g", 123456.0, "123456."], - //["%#g", 1234567.0, "1.234567e+06"], - // the line above is incorrect in go (according to - // my posix reading) %f-> prec = prec-1 - ["%#g", 1234567.0, "1.23457e+06"], - ["%#g", 1230000.0, "1.23000e+06"], - ["%#g", 1000000.0, "1.00000e+06"], - ["%#.0f", 1.0, "1."], - ["%#.0e", 1.0, "1.e+00"], - ["%#.0g", 1.0, "1."], - ["%#.0g", 1100000.0, "1.e+06"], - ["%#.4f", 1.0, "1.0000"], - ["%#.4e", 1.0, "1.0000e+00"], - ["%#.4g", 1.0, "1.000"], - ["%#.4g", 100000.0, "1.000e+05"], - ["%#.0f", 123.0, "123."], - ["%#.0e", 123.0, "1.e+02"], - ["%#.0g", 123.0, "1.e+02"], - ["%#.4f", 123.0, "123.0000"], - ["%#.4e", 123.0, "1.2300e+02"], - ["%#.4g", 123.0, "123.0"], - ["%#.4g", 123000.0, "1.230e+05"], - ["%#9.4g", 1.0, " 1.000"], - // The sharp flag has no effect for binary float format. - // ["%#b", 1.0, "4503599627370496p-52"], // TODO binary for floats - // Precision has no effect for binary float format. - //["%.4b", float32(1.0), "8388608p-23"], // TODO s.above - // ["%.4b", -1.0, "-4503599627370496p-52"], - // Test correct f.intbuf boundary checks. - //["%.68f", 1.0, zeroFill("1.", 68, "")], // TODO zerofill - //["%.68f", -1.0, zeroFill("-1.", 68, "")], //TODO s.a. - // float infinites and NaNs - ["%f", Number.POSITIVE_INFINITY, "+Inf"], - ["%.1f", Number.NEGATIVE_INFINITY, "-Inf"], - ["% f", NaN, " NaN"], - ["%20f", Number.POSITIVE_INFINITY, " +Inf"], - // ["% 20F", Number.POSITIVE_INFINITY, " Inf"], // TODO : wut? - ["% 20e", Number.NEGATIVE_INFINITY, " -Inf"], - ["%+20E", Number.NEGATIVE_INFINITY, " -Inf"], - ["% +20g", Number.NEGATIVE_INFINITY, " -Inf"], - ["%+-20G", Number.POSITIVE_INFINITY, "+Inf "], - ["%20e", NaN, " NaN"], - ["% +20E", NaN, " +NaN"], - ["% -20g", NaN, " NaN "], - ["%+-20G", NaN, "+NaN "], - // Zero padding does not apply to infinities and NaN. - ["%+020e", Number.POSITIVE_INFINITY, " +Inf"], - ["%-020f", Number.NEGATIVE_INFINITY, "-Inf "], - ["%-020E", NaN, "NaN "], - // complex values // go specific - // old test/fmt_test.go - ["%e", 1.0, "1.000000e+00"], - ["%e", 1234.5678e3, "1.234568e+06"], - ["%e", 1234.5678e-8, "1.234568e-05"], - ["%e", -7.0, "-7.000000e+00"], - ["%e", -1e-9, "-1.000000e-09"], - ["%f", 1234.5678e3, "1234567.800000"], - ["%f", 1234.5678e-8, "0.000012"], - ["%f", -7.0, "-7.000000"], - ["%f", -1e-9, "-0.000000"], - // ["%g", 1234.5678e3, "1.2345678e+06"], - // I believe the above test from go is incorrect according to posix, s. above. - ["%g", 1234.5678e3, "1.23457e+06"], - //["%g", float32(1234.5678e3), "1.2345678e+06"], - //["%g", 1234.5678e-8, "1.2345678e-05"], // posix, see above - ["%g", 1234.5678e-8, "1.23457e-05"], - ["%g", -7.0, "-7"], - ["%g", -1e-9, "-1e-09"], - //["%g", float32(-1e-9), "-1e-09"], - ["%E", 1.0, "1.000000E+00"], - ["%E", 1234.5678e3, "1.234568E+06"], - ["%E", 1234.5678e-8, "1.234568E-05"], - ["%E", -7.0, "-7.000000E+00"], - ["%E", -1e-9, "-1.000000E-09"], - //["%G", 1234.5678e3, "1.2345678E+06"], // posix, see above - ["%G", 1234.5678e3, "1.23457E+06"], - //["%G", float32(1234.5678e3), "1.2345678E+06"], - //["%G", 1234.5678e-8, "1.2345678E-05"], // posic, see above - ["%G", 1234.5678e-8, "1.23457E-05"], - ["%G", -7.0, "-7"], - ["%G", -1e-9, "-1E-09"], - //["%G", float32(-1e-9), "-1E-09"], - ["%20.5s", "qwertyuiop", " qwert"], - ["%.5s", "qwertyuiop", "qwert"], - ["%-20.5s", "qwertyuiop", "qwert "], - ["%20c", "x".charCodeAt(0), " x"], - ["%-20c", "x".charCodeAt(0), "x "], - ["%20.6e", 1.2345e3, " 1.234500e+03"], - ["%20.6e", 1.2345e-3, " 1.234500e-03"], - ["%20e", 1.2345e3, " 1.234500e+03"], - ["%20e", 1.2345e-3, " 1.234500e-03"], - ["%20.8e", 1.2345e3, " 1.23450000e+03"], - ["%20f", 1.23456789e3, " 1234.567890"], - ["%20f", 1.23456789e-3, " 0.001235"], - ["%20f", 12345678901.23456789, " 12345678901.234568"], - ["%-20f", 1.23456789e3, "1234.567890 "], - ["%20.8f", 1.23456789e3, " 1234.56789000"], - ["%20.8f", 1.23456789e-3, " 0.00123457"], - // ["%g", 1.23456789e3, "1234.56789"], - // posix ... precision(2) = precision(def=6) - (exp(3)+1) - ["%g", 1.23456789e3, "1234.57"], - // ["%g", 1.23456789e-3, "0.00123456789"], posix... - ["%g", 1.23456789e-3, "0.00123457"], // see above prec6 = precdef6 - (-3+1) - //["%g", 1.23456789e20, "1.23456789e+20"], - ["%g", 1.23456789e20, "1.23457e+20"], - // arrays - // TODO(bartlomieju): - // slice : go specific - - // TODO(bartlomieju): decide how to handle deeper types, arrays, objects - // byte arrays and slices with %b,%c,%d,%o,%U and %v - // f.space should and f.plus should not have an effect with %v. - // f.space and f.plus should have an effect with %d. - - // Padding with byte slices. - // Same for strings - ["%2x", "", " "], // 103 - ["%#2x", "", " "], - ["% 02x", "", "00"], - ["%# 02x", "", "00"], - ["%-2x", "", " "], - ["%-02x", "", " "], - ["%8x", "\xab", " ab"], - ["% 8x", "\xab", " ab"], - ["%#8x", "\xab", " 0xab"], - ["%# 8x", "\xab", " 0xab"], - ["%08x", "\xab", "000000ab"], - ["% 08x", "\xab", "000000ab"], - ["%#08x", "\xab", "00000xab"], - ["%# 08x", "\xab", "00000xab"], - ["%10x", "\xab\xcd", " abcd"], - ["% 10x", "\xab\xcd", " ab cd"], - ["%#10x", "\xab\xcd", " 0xabcd"], - ["%# 10x", "\xab\xcd", " 0xab 0xcd"], - ["%010x", "\xab\xcd", "000000abcd"], - ["% 010x", "\xab\xcd", "00000ab cd"], - ["%#010x", "\xab\xcd", "00000xabcd"], - ["%# 010x", "\xab\xcd", "00xab 0xcd"], - ["%-10X", "\xab", "AB "], - ["% -010X", "\xab", "AB "], - ["%#-10X", "\xab\xcd", "0XABCD "], - ["%# -010X", "\xab\xcd", "0XAB 0XCD "], - // renamings - // Formatter - // GoStringer - - // %T TODO possibly %#T object(constructor) - ["%T", {}, "object"], - ["%T", 1, "number"], - ["%T", "", "string"], - ["%T", undefined, "undefined"], - ["%T", null, "object"], - ["%T", S, "function"], - ["%T", true, "boolean"], - ["%T", Symbol(), "symbol"], - // %p with pointers - - // erroneous things - // {"", nil, "%!(EXTRA <nil>)"}, - // {"", 2, "%!(EXTRA int=2)"}, - // {"no args", "hello", "no args%!(EXTRA string=hello)"}, - // {"%s %", "hello", "hello %!(NOVERB)"}, - // {"%s %.2", "hello", "hello %!(NOVERB)"}, - // {"%017091901790959340919092959340919017929593813360", 0, - // "%!(NOVERB)%!(EXTRA int=0)"}, - // {"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"}, - // // Extra argument errors should format without flags set. - // {"%010.2", "12345", "%!(NOVERB)%!(EXTRA string=12345)"}, - // - // // Test that maps with non-reflexive keys print all keys and values. - // {"%v", map[float64]int{NaN: 1, NaN: 1}, "map[NaN:1 NaN:1]"}, - - // more floats - - ["%.2f", 1.0, "1.00"], - ["%.2f", -1.0, "-1.00"], - ["% .2f", 1.0, " 1.00"], - ["% .2f", -1.0, "-1.00"], - ["%+.2f", 1.0, "+1.00"], - ["%+.2f", -1.0, "-1.00"], - ["%7.2f", 1.0, " 1.00"], - ["%7.2f", -1.0, " -1.00"], - ["% 7.2f", 1.0, " 1.00"], - ["% 7.2f", -1.0, " -1.00"], - ["%+7.2f", 1.0, " +1.00"], - ["%+7.2f", -1.0, " -1.00"], - ["% +7.2f", 1.0, " +1.00"], - ["% +7.2f", -1.0, " -1.00"], - ["%07.2f", 1.0, "0001.00"], - ["%07.2f", -1.0, "-001.00"], - ["% 07.2f", 1.0, " 001.00"], //153 here - ["% 07.2f", -1.0, "-001.00"], - ["%+07.2f", 1.0, "+001.00"], - ["%+07.2f", -1.0, "-001.00"], - ["% +07.2f", 1.0, "+001.00"], - ["% +07.2f", -1.0, "-001.00"], -]; - -Deno.test("testThorough", function (): void { - tests.forEach((t, i): void => { - // p(t) - const is = S(t[0], t[1]); - const should = t[2]; - assertEquals( - is, - should, - `failed case[${i}] : is >${is}< should >${should}<`, - ); - }); -}); - -Deno.test("testWeirdos", function (): void { - assertEquals(S("%.d", 9), "9"); - assertEquals( - S("dec[%d]=%d hex[%[1]d]=%#x oct[%[1]d]=%#o %s", 1, 255, "Third"), - "dec[1]=255 hex[1]=0xff oct[1]=0377 Third", - ); -}); - -Deno.test("formatV", function (): void { - const a = { a: { a: { a: { a: { a: { a: { a: {} } } } } } } }; - assertEquals(S("%v", a), "[object Object]"); - assertEquals(S("%#v", a), `{ a: { a: { a: { a: [Object] } } } }`); - assertEquals( - S("%#.8v", a), - "{ a: { a: { a: { a: { a: { a: { a: {} } } } } } } }", - ); - assertEquals(S("%#.1v", a), `{ a: [Object] }`); -}); - -Deno.test("formatJ", function (): void { - const a = { a: { a: { a: { a: { a: { a: { a: {} } } } } } } }; - assertEquals(S("%j", a), `{"a":{"a":{"a":{"a":{"a":{"a":{"a":{}}}}}}}}`); -}); - -Deno.test("flagLessThan", function (): void { - const a = { a: { a: { a: { a: { a: { a: { a: {} } } } } } } }; - const aArray = [a, a, a]; - assertEquals( - S("%<#.1v", aArray), - `[ { a: [Object] }, { a: [Object] }, { a: [Object] } ]`, - ); - const fArray = [1.2345, 0.98765, 123456789.5678]; - assertEquals(S("%<.2f", fArray), "[ 1.23, 0.99, 123456789.57 ]"); -}); - -Deno.test("testErrors", function (): void { - // wrong type : TODO strict mode ... - //assertEquals(S("%f", "not a number"), "%!(BADTYPE flag=f type=string)") - assertEquals(S("A %h", ""), "A %!(BAD VERB 'h')"); - assertEquals(S("%J", ""), "%!(BAD VERB 'J')"); - assertEquals(S("bla%J", ""), "bla%!(BAD VERB 'J')"); - assertEquals(S("%Jbla", ""), "%!(BAD VERB 'J')bla"); - - assertEquals(S("%d"), "%!(MISSING 'd')"); - assertEquals(S("%d %d", 1), "1 %!(MISSING 'd')"); - assertEquals(S("%d %f A", 1), "1 %!(MISSING 'f') A"); - - assertEquals(S("%*.2f", "a", 1.1), "%!(BAD WIDTH 'a')"); - assertEquals(S("%.*f", "a", 1.1), "%!(BAD PREC 'a')"); - assertEquals( - S("%.[2]*f", 1.23, "p"), - `%!(BAD PREC 'p')%!(EXTRA '1.23')`, - ); - assertEquals(S("%.[2]*[1]f Yippie!", 1.23, "p"), "%!(BAD PREC 'p') Yippie!"); - - assertEquals(S("%[1]*.2f", "a", "p"), "%!(BAD WIDTH 'a')"); - - assertEquals(S("A", "a", "p"), `A%!(EXTRA '"a"' '"p"')`); - assertEquals(S("%[2]s %[2]s", "a", "p"), `p p%!(EXTRA '"a"')`); - - // remains to be determined how to handle bad indices ... - // (realistically) the entire error handling is still up for grabs. - assertEquals(S("%[hallo]s %d %d %d", 1, 2, 3, 4), "%!(BAD INDEX) 2 3 4"); - assertEquals( - S("%[5]s", 1, 2, 3, 4), - `%!(BAD INDEX)%!(EXTRA '2' '3' '4')`, - ); - assertEquals(S("%[5]f"), "%!(BAD INDEX)"); - assertEquals(S("%.[5]f"), "%!(BAD INDEX)"); - assertEquals(S("%.[5]*f"), "%!(BAD INDEX)"); -}); |