Formatting and printing string utilities.
The purpose of this project is to provide minimum replacement formatting solution.
Existing formatting solutions offer multiple features.
The Deno community already has std/fmt::sprintf. There are also various other 3rd party libraries.
These could accomplish a lot of work. On the other hand, they are somewhat over-specified. You have to pay more cost than you need to. (cost here refers to code size and execution speed).
We decompose formatting into replacement and serialization. Then, focus on replacement.
deno:
deno add @miyauci/format
npm:
npx jsr add @miyauci/format
Type inference works well for template literal.
import { format } from "@miyauci/format";
import { assertEquals } from "@std/assert";
assertEquals(format("{0} {name}!", { 0: "Hello", name: "Tom" }), "Hello Tom!");
//@ts-expect-error it should provide params.0 and params.name
format("{0} {name}!", {});
If the specifier is numeric only, you can specify an array as an parameters.
import { format } from "@miyauci/format";
import { assertEquals } from "@std/assert";
assertEquals(format("{0} world!", ["Hello"]), "Hello world!");
//@ts-expect-error it should provide params.0
format("{0} world!", []);
Placeholder is a pair of prefix and suffix.
Name | Default |
---|---|
prefix | { |
suffix | } |
This can be changed.
Template literal style:
import { format } from "@miyauci/format";
import { assertEquals } from "@std/assert";
const result = format("should be ${expected}, actual ${actual}", {
expected: "string",
actual: "number",
}, { placeholders: [{ prefix: "${", suffix: "}" }] });
assertEquals(result, "should be string, actual number");
//@ts-expect-error it should be error
format("should be ${expected}, actual ${actual}", {}, {
placeholders: [{ prefix: "${", suffix: "}" }],
});
Percent style:
import { format } from "@miyauci/format";
import { assertEquals } from "@std/assert";
const result = format("Hello %s!!!", { "": "world" }, {
placeholders: [{ prefix: "%", suffix: "s" }],
});
assertEquals(result, "Hello world!!!");
Multiple placeholders:
import { format } from "@miyauci/format";
import { assertEquals } from "@std/assert";
const result = format("[0] {description}", {
0: new Date("2038/1/19 03:14:08"),
description: "Time stopped",
}, {
placeholders: [
{ prefix: "{", suffix: "}" },
{ prefix: "[", suffix: "]" },
],
});
assertEquals(result, "<Date::toString> Time stopped");
The computational complexity of placeholder is O(n) compared to parameters. It is recommended to reduce the number of placeholders as much as possible.
Parameter serialization uses the String
constructor by default.
To change this, specify the stringify
option.
import { format } from "@miyauci/format";
import { assertEquals } from "@std/assert";
const result = format("{0}{1}{2}", ["1", 1, true], {
stringify: (param) => {
if (typeof param === "string") return `"${param}"`;
return String(param);
},
});
assertEquals(result, `"1"1true`);
In certain circumstances, template literal types cannot be provided. In such cases, generics can be specified.
import { format } from "@miyauci/format";
import { assertEquals } from "@std/assert";
declare const string: string;
//@ts-expect-error it should provide params.name and params.title
format<"name" | "title">(string, {});
format
does not throw an error. Even if a parameter is missing.
If type inference is working, there will never be a missing parameter. Therefore, no parameter checking is done at runtime.
The following is valid.
import { format } from "@miyauci/format";
import { assertEquals } from "@std/assert";
assertEquals(format<"0">("{0}{1}", ["false"]), "false{1}");
If you specify generics, you must guarantee the parameters.
This also allows you to escape placeholder.
See performance.
See jsr doc for all APIs.
See contributing.
MIT © 2023 Tomoki Miyauchi