rsformat 0.2.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,170 +1,161 @@
1
- # RSFormat
2
-
3
- RSFormat is a string formatting/printing library for JavaScript. It offers a minimal, yet powerful and flexible alternative to the string formatting and printing provided by `console.log`.
4
-
5
- ## Motivation
6
-
7
- `console.log` is an odd method: its output can be affected by functions called before/after it (such as `console.group`), or their order affected by what parameters there are. For example, when calling `console.log(string, number)`, number can come either after or inside `string` depending on the value of `string`.
8
-
9
- RSFormat provides alternative functions with standardised behaviour: its `format`, `println` and all other functions will always output in the same manner, and have a standardised syntax which will only print the initial string, formatted with the parameters provided afterwards.
10
-
11
- Rust formatting also includes a lot of convenient operators for formatting text, such as padding/alignment, printing numbers in a given base, specifying decimal precision, etc.. This makes it a more ergonomic and convenient approach to printing things to the console.
12
-
13
- ## Usage
14
-
15
- you can install rsformat using [npm](https://www.npmjs.com/package/rsformat):
16
-
17
- ```
18
- npm install rsformat
19
- ```
20
-
21
- ### Basic formatting and printing to console
22
-
23
- RSFormat functions are called using a format string, and any number of format arguments following it.
24
-
25
- Any instance of `{}` in the format strings will get replaced with a value.
26
-
27
- You can specify what value you want in the parameters by using a number inside the insertion point.
28
-
29
- ```js
30
- import { format, println } from 'rsformat'; // ESM
31
- const { format, println } = require('rsformat'); // CommonJS
32
-
33
- let name = 'everyone';
34
-
35
- let greeting = format('Hello {}!', name); // Evaluates to the string 'Hello, everyone!'
36
-
37
- println('I have {1} apples and {0} oranges', 13, 14); // Will print 'I have 14 apples and 13 oranges' to the console
38
- ```
39
-
40
- ### Format Specifiers
41
-
42
- Format specifiers can be used by adding `:` inside the insertion point (after the optional argument number), and will format the value differently inside the string. See the [rust format docs](https://doc.rust-lang.org/std/fmt/#syntax) for more detailed information on format specifiers.
43
-
44
- This implementation differs from the rust one in a few ways:
45
-
46
- - Named arguments before or in format specifiers or in values aren't allowed, only numbers can be used.
47
- - The `-` sign (unused in rust) is unsupported.
48
- - Pointer format type `p` is unsupported.
49
- - Hexadecimal debug types `x?` and `X?` are unsupported.
50
- - Specifying precision with `*` is unsupported.
51
-
52
- #### Different formatting types
53
-
54
- ```js
55
- // Debug format specifier: ?, uses util.inspect rather than toString
56
-
57
- println('{}', { a: 1 }); //prints '[object Object]'
58
- println('{:?}', { a: 1 }); //prints "{ a:1 }"
59
-
60
- // Number base specifiers: x, X, b, o - for lower/uppercase hexadecimal, binary, octal
61
-
62
- format('{} is {0:x} in hex, {0:b} in binary and {0:o} in octal', 15); // '15 is f in hex, 1111 in binary and 17 in octal'
63
-
64
- // Scientific notation specifiers: e, E - for lower/uppercase scientific notation
65
-
66
- let hugeNumber = 1000n;
67
- format('{:E}', hugeNumber); // '1E3';
68
- ```
69
-
70
- #### Padding, Alignment
71
-
72
- Values can be aligned using any fill character (will default to a space ` `), and either left, center or right aligned with `<`, `^` or `>` respectively (will default to right alignment `>`). You will also have to specify a width with an integer after the alignment:
73
-
74
- ```js
75
- /*
76
- Will print a pyramid of 'a's:
77
- ' a '
78
- ' aaa '
79
- 'aaaaa'
80
- */
81
- let pyramidLevels = ['a', 'aaa', 'aaaaa'];
82
- for(let value of pyramidLevels) {
83
- println('{:^5}', value);
84
- }
85
- ```
86
-
87
- ```js
88
- format('{:.>7}', [1,2]); // '....1,2'
89
- ```
90
-
91
- #### Pretty Printing
92
-
93
- In some instances (namely debug, binary, octal and hexadecimal formatting), adding a `#` before the format specifier will use an alternative 'pretty' printing style. This amounts to using non-compact `util.inspect` for debug printing (spanning multiple lines), and adding 0b/0o/0x as a prefix for the numbers formatted as powers of two.
94
-
95
- ```js
96
- format('{:#X}', 255); // '0xFF'
97
- ```
98
-
99
- #### Specific Number Formatting
100
-
101
- Specifically for `number` and `bigint` values, a 0 can be placed before the width to pad the number with 0s instead. This will account for signs and possible formatting differences.
102
-
103
- ```js
104
- format('{:#07x}', 15) // '0x0000F'
105
- ```
106
-
107
- Decimal precision can be specified for numbers by adding a . and specifying an integer for precision.
108
-
109
- ```js
110
- format('{:.3}', 1.23456789); // '1.234'
111
- format('{:.3}', -1); // '-1.000'
112
- ```
113
-
114
- Adding a + to the formatting specifier will print the sign regardless of whether the number is negative.
115
-
116
- ```js
117
- format('{:+}', 1); // '+1'
118
- ```
119
-
120
- ## Custom output
121
-
122
- If you want to use the print function to output to anything other than `process.stdout` and `process.stderr`, you can import the `Printer` function to create your own print functions, using any output and error streams that are instances of node's `Writable`.
123
-
124
- ```ts
125
- // Custom output example (ts)
126
- import { Printer } from 'rsformat/print';
127
- import { Writable } from 'stream';
128
-
129
- let someOutputStream: Writable = /* ... */;
130
- let someErrorStream: Writable = /* ... */;
131
-
132
- let { print, println, eprint, eprintln } = Printer(someOutputStream, someErrorStream);
133
- ```
134
-
135
- ## A Note on Performance
136
-
137
- You might think that these utilities might have a performance impact on RSFormat's printing functions. And while they do, the functions are still consistently faster than `console.log`.
138
-
139
- A simple benchmark setup like the one below will demonstrate that `println` is more performant, even when doing things like base conversions and text alignment, compared to `console.log` logging a simple string:
140
-
141
- ```js
142
- // benchmark.mjs
143
- import { println } from 'rsformat';
144
-
145
- const time = (fn, iter) => {
146
- let time = Date.now();
147
- while (iter-- > 0) {
148
- fn();
149
- }
150
- return Date.now() - time;
151
- }
152
-
153
- let iterations = 100000;
154
-
155
- let logTime = time(() => console.log('hello'), iterations);
156
- let printlnTime = time(() => println('{:>+#7X}', 255), iterations);
157
-
158
- println('console.log time for {} executions: {}ms', iterations, logTime);
159
- println('rsformat.println time for {} executions: {}ms', iterations, printlnTime);
160
- ```
161
-
162
- ```
163
- > node benchmark.mjs
164
- ...After a lot of output...
165
-
166
- console.log time for 100000 executions: 7217ms
167
- rsformat.println time for 100000 executions: 5900ms
168
- ```
169
-
170
- _Tested on node.js using a Windows laptop on an Intel core I7-1360P, on battery power. Performance will vary, but this benchmark was just to show that RSFormat has no performance penalty._
1
+ # RSFormat
2
+
3
+ RSFormat is a string formatting/printing library for JavaScript. It offers a minimal, yet powerful and flexible alternative to the string formatting and printing provided by `console.log`.
4
+
5
+ ```js
6
+ import { rs, println } from 'rsformat';
7
+
8
+ let s = rs`${15} is ${15}:#X in hex`;
9
+ // s == '15 is 0xF in hex'
10
+
11
+ println(rs`${'a'}:^5`);
12
+ // Prints ' a '
13
+ ```
14
+
15
+ ## Motivation
16
+
17
+ `console.log` is an odd method: its output can be affected by functions called before/after it (such as `console.group`), or their order affected by what parameters there are. For example, when calling `console.log(string, number)`, number can come either after or inside `string` depending on the value of `string`.
18
+
19
+ This behaviour has largely been superseded at a language level by template literals, which allow formatting of parameters directly inside the templates, causing these methods to have unnecessary overhead and undesired behaviour.
20
+
21
+ RSFormat builds onto template literals by implementing Rust-style format specifiers and lightweight printing functions. Rust formatting includes a lot of convenient operators for formatting text, such as padding/alignment, printing numbers in a given base, specifying decimal precision, etc.
22
+
23
+ ## Usage
24
+
25
+ You can install RSFormat from [npm](https://www.npmjs.com/package/rsformat):
26
+
27
+ ```sh
28
+ npm install rsformat
29
+ ```
30
+
31
+ ### Basic formatting and printing to console
32
+
33
+ The `rs` template tag can be used to enable rust-style formatting in a template.
34
+ To reference a previous or following argument, use `rs.ref` with the parameter number.
35
+
36
+ ```js
37
+ import { rs, println } from 'rsformat'; // ESM
38
+ const { rs, println } = require('rsformat'); // CommonJS
39
+
40
+ let number = 15;
41
+
42
+ let info = rs`${number} is ${rs.ref(0)}:x in hex`; // info == '15 is f in hex'
43
+ ```
44
+
45
+ > NB: templates tagged with `rs` are instances of a special class `RsString` that extends `String`, rather than a primitive value. This is to enable colors for debug formatting inside the printing functions. This difference should not affect normal usage, but `rs.raw` can be used as an alternative tag to get a primitive `string`.
46
+
47
+ The printing functions can be called with plain strings, instances of `String` or templates formatted with `rs`:
48
+
49
+ ```ts
50
+ println('Hello World');
51
+ println(rs`...`);
52
+ ```
53
+
54
+ ### Format Specifiers
55
+
56
+ Format specifiers can be used by adding `:` after the format argument, and will format the value differently inside the string. See the [rust format docs](https://doc.rust-lang.org/std/fmt/) for more detailed information on format specifiers.
57
+
58
+ This implementation differs from the Rust one in a few ways:
59
+
60
+ - Rather than escaping the braces using `{{` or `}}`, the formatting colon can be escaped using `::`.
61
+ - Different parameters are referenced using `rs.ref(n)` rather than the number literal `n`.
62
+ - To separate a formatting specifier from the rest of the string without adding a space, an extra closing colon must be added (eg. `:#?:foo` - specifier gets parsed as `:#?`)
63
+ - The `-` sign (unused in Rust) will add a space if the number is positive to align it with negative numbers without showing a `+`.
64
+ - Pointer format type `p` is unsupported.
65
+ - Hexadecimal debug types `x?` and `X?` are unsupported.
66
+ - Specifying precision dynamically with `*` is unsupported. Instead, precision and width can both be specified dynamically by using a separate number parameter in place of the number.
67
+ - New format types have been added:
68
+ - `N` for uppercase ordinal suffixing of numbers (rounded to integers)
69
+ - `n` for lowercase ordinal suffixing of numbers (rounded to integers)
70
+
71
+ #### Different formatting types
72
+
73
+ The debug format specifier `?` uses `util.inspect` to stringify the parameter rather than `toString`.
74
+
75
+ ```js
76
+ let obj = { a: 1 };
77
+ println(rs`${obj}`); // prints '[object Object]'
78
+ println(rs`${obj}:?`); // prints '{ a: 1 }'
79
+ ```
80
+
81
+ The provided printing functions will display colors in the output of `util.inspect`, but otherwise it will be formatted without color.
82
+
83
+ The specifiers `b`,`o`,`x`,`X`,`e`,`E`,`n`,`N` will convert a `number` or `bigint` parameter to:
84
+ - `b`: binary
85
+ - `o`: octal
86
+ - `x`/`X`: lowercase/uppercase hexadecimal
87
+ - `e`/`E`: lowercase/uppercase scientific notation
88
+ - `n`/`N`: lowercase/uppercase ordinal suffixed string (rounded to integer)
89
+
90
+ ```js
91
+ let advancedInfo = (n) => rs`${n} is ${n}:x in hex, ${n}:b in binary and ${n}:o in octal`;
92
+
93
+ advancedInfo(15); // '15 is f in hex, 1111 in binary and 17 in octal'
94
+
95
+ let hugeNumber = 1000n;
96
+ let science = rs`${hugeNumber}:E`; // '1E3'
97
+ let ordinal = rs`${hugeNumber}:n`; // '1000th'
98
+ ```
99
+
100
+ #### Padding, Alignment
101
+
102
+ Values can be aligned using any fill character (will default to a space ` `), and either left, center or right aligned with `<`, `^` or `>` respectively (will default to right alignment `>`). You will also have to specify a width with an integer after the alignment, or provide a separate number parameter.
103
+
104
+ ```js
105
+ /*
106
+ Will print a pyramid of 'a's:
107
+ ' a '
108
+ ' aaa '
109
+ 'aaaaa'
110
+ */
111
+ let pyramidLevels = ['a', 'aaa', 'aaaaa'];
112
+ for(let value of pyramidLevels) {
113
+ println(rs`${value}:^5`);
114
+ }
115
+ ```
116
+
117
+ ```js
118
+ rs`${[1,2]}:.>${7}` // '....1,2'
119
+ ```
120
+
121
+ #### Pretty Printing
122
+
123
+ In some instances (namely debug, binary, octal and hexadecimal formatting), adding a `#` before the format specifier will use an alternative 'pretty' printing style. This amounts to using multiline `util.inspect` for debug printing (spanning multiple lines), and adding `0b`/`0o`/`0x` as a prefix for the numbers in the respective bases.
124
+
125
+ ```js
126
+ rs`${255}:#X` // '0xFF'
127
+ ```
128
+
129
+ #### Specific Number Formatting
130
+
131
+ Specifically for `number` and `bigint` values, a `0` can be placed before the width to pad the number with zeroes instead. This will account for signs and possible formatting differences.
132
+
133
+ ```js
134
+ rs`${15}:#07x` // '0x0000F'
135
+ ```
136
+
137
+ Decimal precision can be specified for numbers by adding a `.` and specifying an integer for precision. An additional parameter can also be provided to do this dynamically.
138
+
139
+ ```js
140
+ rs`${1.23456789}:.3` // '1.234'
141
+ rs`${-1}:.${3}` // '-1.000'
142
+ ```
143
+
144
+ Adding a `+` to the formatting specifier will print the sign regardless of whether the number is negative.
145
+ Adding a `-` will instead add a space if the number is positive.
146
+
147
+ ```js
148
+ rs`${1}:+` // '+1'
149
+ rs`${1}:-` // ' 1'
150
+ ```
151
+
152
+ ## Older versions of RSFormat
153
+
154
+ Versions of RSFormat on npm prior to `1.0.0` provide formatting and printing functions that are more similar in syntax to Rust, using plain strings instead of tagged templates:
155
+
156
+ ```js
157
+ import { format } from 'rsformat';
158
+ format('{} is {0:#x} in hex', 15); // '15 is 0xf in hex'
159
+ ```
160
+
161
+ See the `old` branch for more detailed documentation. The last version to use this formatting was `0.2.5`.
package/lib/format.d.ts CHANGED
@@ -1,17 +1,45 @@
1
1
  /**
2
- * Format a string similarly to rust's format! macro.
2
+ * Type representing a string formatted by `rs`.
3
+ * An extension of `String`.
4
+ */
5
+ export declare class RsString extends String {
6
+ __debugColors: boolean;
7
+ private cachedColor;
8
+ private cachedPlain;
9
+ private strings;
10
+ private params;
11
+ constructor(strings: TemplateStringsArray, params: any[]);
12
+ toString(): string;
13
+ valueOf(): string;
14
+ }
15
+ /**
16
+ * Format a template literal with rust-style formatting and return it as a string.
3
17
  *
4
- * @param str String used for formatting
5
- * @param params Parameters to be inserted into the format string
18
+ * @param strings String parts of the template
19
+ * @param params Template parameters
20
+ * @returns a string primitive of the formatted string
6
21
  */
7
- export declare function format(str: string, ...params: any[]): string;
22
+ export declare function buildString(strings: TemplateStringsArray, params: any[], debugColors?: boolean): string;
23
+ type AlignDirection = '<' | '^' | '>';
24
+ type Sign = '-' | '+' | '';
25
+ type FormatType = '?' | 'o' | 'x' | 'X' | 'b' | 'e' | 'E' | 'n' | 'N' | '';
26
+ type FormatSpecifier = {
27
+ fill: string;
28
+ align: AlignDirection;
29
+ force_sign: Sign;
30
+ pretty: boolean;
31
+ pad_zeroes: boolean;
32
+ width: number;
33
+ precision: number;
34
+ type: FormatType;
35
+ };
8
36
  /**
9
- * Raw formatting behaviour function called by `format` and printing functions.
37
+ * Format a parameter as a string according to a specifier.
10
38
  *
11
- * @param str String used for formatting
12
- * @param params Parameters to be inserted into the format string
13
- * @param options Options passed into formatting (Whether to use colors in debug formatting - false by default)
39
+ * @param param parameter to format
40
+ * @param format format specifier object
41
+ * @param debugColors whether to use colors in debug formatting
42
+ * @returns `param` as a formatted string
14
43
  */
15
- export declare function fmt_raw(str: string, params: any[], options?: {
16
- colors: boolean;
17
- }): string;
44
+ export declare function formatParam(param: any, format: FormatSpecifier, debugColors: boolean): string;
45
+ export {};
package/lib/format.js CHANGED
@@ -1,212 +1,339 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.format = format;
4
- exports.fmt_raw = fmt_raw;
5
- const node_util_1 = require("node:util");
6
+ exports.formatParam = exports.buildString = exports.RsString = void 0;
7
+ const node_util_1 = __importDefault(require("node:util"));
8
+ const is_digit = (c) => c >= '0' && c <= '9';
9
+ const error = (param, char, reason) => new Error(`rs[param ${param}, char ${char}] ${reason}`);
6
10
  /**
7
- * Regex to match for possible formatting insertion points.
8
- * Similar to the way formatting is parsed in rust,
9
- * but with a few key differences:
10
- * - Named arguments before format specifiers aren't allowed, only numbers can be used.
11
- * - The - sign (unused in rust) is unsupported.
12
- * - Pointer format type 'p' is unsupported.
13
- * - Hexadecimal debug types 'x?' and 'X?' are unsupported.
14
- * - Specifying precision with * is unsupported.
15
- *
16
- * The formatter currently matches with a regex
17
- * instead of a full-blown parser for simplicity
18
- * and performance, as built-in regex matching is
19
- * likely to be faster than a js-implemented parser.
20
- * However, this will not match incorrectly formatted
21
- * insertion points.
11
+ * Type representing a string formatted by `rs`.
12
+ * An extension of `String`.
22
13
  */
23
- const FORMAT_REGEX = (/\{{2}|\}{2}|\{(\d*?)(?::(?:(.?)(\^|>|<))?(\+)?(#)?(0)?(\d*)?(\.\d*)?(\?|o|x|X|b|e|E)?)?\}/g);
24
- /**
25
- * Format a string similarly to rust's format! macro.
26
- *
27
- * @param str String used for formatting
28
- * @param params Parameters to be inserted into the format string
29
- */
30
- function format(str, ...params) {
31
- return fmt_raw(str, params);
14
+ class RsString extends String {
15
+ __debugColors = false;
16
+ cachedColor = null;
17
+ cachedPlain = null;
18
+ strings;
19
+ params;
20
+ constructor(strings, params) {
21
+ super('[use rs.raw to get string primitive]');
22
+ Object.defineProperties(this, {
23
+ strings: { value: strings, enumerable: false },
24
+ params: { value: params, enumerable: false },
25
+ cachedPlain: { value: null, writable: true, enumerable: false },
26
+ cachedColor: { value: null, writable: true, enumerable: false },
27
+ __debugColors: { value: false, writable: true, enumerable: false },
28
+ });
29
+ }
30
+ toString() {
31
+ if (this.__debugColors) {
32
+ if (this.cachedColor === null)
33
+ this.cachedColor = buildString(this.strings, this.params, true);
34
+ return this.cachedColor;
35
+ }
36
+ else {
37
+ if (this.cachedPlain === null)
38
+ this.cachedPlain = buildString(this.strings, this.params, false);
39
+ return this.cachedPlain;
40
+ }
41
+ ;
42
+ }
43
+ valueOf() {
44
+ return this.toString();
45
+ }
32
46
  }
47
+ exports.RsString = RsString;
33
48
  /**
34
- * Raw formatting behaviour function called by `format` and printing functions.
49
+ * Format a template literal with rust-style formatting and return it as a string.
35
50
  *
36
- * @param str String used for formatting
37
- * @param params Parameters to be inserted into the format string
38
- * @param options Options passed into formatting (Whether to use colors in debug formatting - false by default)
51
+ * @param strings String parts of the template
52
+ * @param params Template parameters
53
+ * @returns a string primitive of the formatted string
39
54
  */
40
- function fmt_raw(str, params, options = { colors: false }) {
41
- // Counter used for insertion of unnumbered values
42
- let param_counter = 0;
43
- str = str.replace(FORMAT_REGEX, ($, $param_number, $fill_character, $align_direction, $sign, $pretty, $pad_zeroes, $width, $precision, $type) => {
44
- // Return a bracket if the regex matched an escaped bracket
45
- if ($ === '{{') {
46
- return '{';
47
- }
48
- if ($ === '}}') {
49
- return '}';
50
- }
51
- // Process parameter number; increment param_counter if not included
52
- let param = $param_number === ''
53
- ? params[param_counter++]
54
- : params[+$param_number];
55
- if (param === undefined) {
56
- throw new Error(`parameter ${$param_number || param_counter - 1} either NaN or not provided`);
57
- }
58
- let param_type = typeof param;
59
- let true_length = -1;
60
- // Process parameter type
61
- switch ($type) {
55
+ function buildString(strings, params, debugColors = false) {
56
+ let out = [strings[0]];
57
+ for (let i = 1; i < strings.length; ++i) {
58
+ let string = strings[i];
59
+ let param = params[i - 1];
60
+ // Resolve parameter references recursively
61
+ while (typeof param == 'object' && '__rs_param_ref' in param) {
62
+ let ref_number = param.__rs_param_ref;
63
+ if (typeof ref_number != 'number'
64
+ || ref_number < 0 || ref_number >= params.length) {
65
+ throw new Error(`Parameter ${i - 1}: Invalid reference`);
66
+ }
67
+ if (ref_number == i - 1)
68
+ throw new Error(`Parameter ${i - 1} references itself recursively`);
69
+ param = params[param.__rs_param_ref];
70
+ }
71
+ // Parse format specifier
72
+ // If the string starts with a single : it has a format specifier,
73
+ // If it has two the first : is being escaped and can be removed
74
+ if (string[0] == ':') {
75
+ if (string[1] == ':') {
76
+ out.push(param.toString() + string.substring(1));
77
+ continue;
78
+ }
79
+ }
80
+ else {
81
+ out.push(param.toString() + string);
82
+ continue;
83
+ }
84
+ ;
85
+ // Keep track of our index in the string to slice the format specifier later
86
+ let idx = 1;
87
+ // Compute format based on string
88
+ let fill = ' ', align = '>', force_sign = '', pretty = false, pad_zeroes = false, width = 0, precision = -1, format_type = '';
89
+ // Fill/align
90
+ // If the next character is align, then the current is the fill
91
+ if (string[idx + 1] == '<' || string[idx + 1] == '^' || string[idx + 1] == '>') {
92
+ fill = string[idx++];
93
+ }
94
+ if (string[idx] == '<' || string[idx] == '^' || string[idx] == '>') {
95
+ align = string[idx++];
96
+ }
97
+ // Force sign
98
+ if (string[idx] == '+' || string[idx] == '-')
99
+ force_sign = string[idx++];
100
+ // Pretty formatting
101
+ if (string[idx] == '#')
102
+ pretty = true, idx++;
103
+ // Padding numbers with zeroes
104
+ if (string[idx] == '0')
105
+ pad_zeroes = true, idx++;
106
+ // Width
107
+ if (is_digit(string[idx])) {
108
+ let width_substring_start = idx++;
109
+ while (is_digit(string[idx]))
110
+ idx++;
111
+ width = Number(string.substring(width_substring_start, idx));
112
+ }
113
+ else if (idx == string.length) {
114
+ // Grab the next parameter and fuse the string with the next one
115
+ width = params[i];
116
+ if (typeof width != 'number')
117
+ throw error(i - 1, idx, `Expected a number or number parameter for width specifier (found ${string[idx] ? "'" + string[idx] + "'" : typeof width + ' parameter'}).\nIf the next parameter was not meant to be a width number, add a : to the end of the formatting specifier.`);
118
+ string += strings[++i];
119
+ }
120
+ // Precision
121
+ if (string[idx] == '.') {
122
+ if (!is_digit(string[++idx])) {
123
+ // Grab the next parameter and fuse the string with the next one
124
+ precision = params[i];
125
+ if (typeof precision != 'number')
126
+ throw error(i - 1, idx, `Expected a number or number parameter for precision specifier after . (found ${string[idx] ? "'" + string[idx] + "'" : typeof width + ' parameter'}).\nIf the next parameter was not meant to be a precision number, add a : to the end of the formatting specifier.`);
127
+ string += strings[++i];
128
+ }
129
+ else {
130
+ let precision_substring_start = idx;
131
+ while (is_digit(string[idx]))
132
+ idx++;
133
+ precision = Number(string.substring(precision_substring_start, idx));
134
+ }
135
+ }
136
+ // Format type
137
+ switch (string[idx]) {
138
+ case '?':
62
139
  case 'o':
63
- param = param.toString(8);
64
- break;
65
140
  case 'x':
66
- param = param.toString(16);
67
- break;
68
141
  case 'X':
69
- param = param.toString(16).toUpperCase();
70
- break;
71
142
  case 'b':
72
- param = param.toString(2);
73
- break;
74
143
  case 'e':
75
- switch (param_type) {
76
- case 'number':
77
- param = param.toExponential();
78
- break;
79
- case 'bigint':
80
- param = param.toLocaleString('en-US', {
81
- notation: 'scientific',
82
- maximumFractionDigits: 20,
83
- }).toLowerCase();
84
- break;
85
- default:
86
- param = param.toString();
87
- break;
88
- }
89
- break;
90
144
  case 'E':
91
- switch (param_type) {
92
- case 'number':
93
- param = param.toExponential().toUpperCase();
94
- break;
95
- case 'bigint':
96
- param = param.toLocaleString('en-US', {
97
- notation: 'scientific',
98
- maximumFractionDigits: 20
99
- });
100
- break;
101
- default:
102
- param = param.toString();
103
- break;
104
- }
105
- break;
106
- case '?':
107
- // Do not force sign or align to precision when using inspect
108
- $sign = undefined;
109
- $precision = undefined;
110
- true_length = (0, node_util_1.inspect)(param, {
111
- depth: Infinity,
112
- colors: false,
113
- compact: $pretty !== '#'
114
- }).length;
115
- param = (0, node_util_1.inspect)(param, {
116
- depth: Infinity,
117
- colors: options.colors,
118
- compact: $pretty !== '#'
119
- });
120
- break;
121
- default:
122
- param = param.toString();
123
- break;
145
+ case 'n':
146
+ case 'N':
147
+ format_type = string[idx++];
124
148
  }
125
- ;
126
- if (true_length == -1) {
127
- true_length = param.length;
128
- }
129
- // Compute radix-point precision on numbers
130
- if (param_type == 'number' && $precision) {
131
- let [pre, post] = param.split('.');
132
- let precision = +$precision.substring(1, $precision.length);
133
- if (!precision) { // precision = 0, do not include radix point
134
- param = pre;
135
- }
136
- else {
137
- post = ((post || '') + '0'.repeat(precision)).slice(0, precision);
138
- param = pre + '.' + post;
139
- }
149
+ // End of specifier
150
+ if (string[idx] == ':') {
151
+ idx++;
140
152
  }
141
- let width;
142
- if ($width === undefined) {
143
- width = 0;
153
+ else if (string[idx] != ' ' && string[idx] !== undefined) {
154
+ throw error(i - 1, idx, `Expected colon (':') or space (' ') at end of formatting specifier (found '${string[idx]}')`);
144
155
  }
145
- else {
146
- width = +$width;
147
- if (Number.isNaN(width))
148
- throw new Error(`invalid width specifier '${$width}' (must be an integer)`);
149
- }
150
- let filled = false;
151
- if ((param_type == 'number') || (param_type == 'bigint')) {
152
- // Compute parameter sign
153
- let maybe_sign = param.substring(0, 1);
154
- if (maybe_sign === '-') {
155
- param = param.substring(1, param.length);
156
+ // Format parameter according to specifier
157
+ let formatted = formatParam(param, {
158
+ fill,
159
+ align,
160
+ force_sign,
161
+ pretty,
162
+ pad_zeroes,
163
+ width,
164
+ precision,
165
+ type: format_type
166
+ }, debugColors);
167
+ out.push(formatted + string.substring(idx));
168
+ }
169
+ return out.join('');
170
+ }
171
+ exports.buildString = buildString;
172
+ /**
173
+ * Format a parameter as a string according to a specifier.
174
+ *
175
+ * @param param parameter to format
176
+ * @param format format specifier object
177
+ * @param debugColors whether to use colors in debug formatting
178
+ * @returns `param` as a formatted string
179
+ */
180
+ function formatParam(param, format, debugColors) {
181
+ let param_type = typeof param;
182
+ let true_length = -1;
183
+ // Process parameter type
184
+ switch (format.type) {
185
+ case 'o':
186
+ param = param.toString(8);
187
+ break;
188
+ case 'x':
189
+ param = param.toString(16);
190
+ break;
191
+ case 'X':
192
+ param = param.toString(16).toUpperCase();
193
+ break;
194
+ case 'b':
195
+ param = param.toString(2);
196
+ break;
197
+ case 'e':
198
+ case 'E':
199
+ if (param_type != 'number' && param_type != 'bigint') {
200
+ param = param.toString();
201
+ break;
156
202
  }
157
- else if ($sign === '+') {
158
- maybe_sign = '+';
203
+ param = param.toLocaleString('en-US', { notation: 'scientific', maximumFractionDigits: 20 });
204
+ if (format.type == 'e')
205
+ param = param.toLowercase();
206
+ break;
207
+ case 'n':
208
+ case 'N':
209
+ if (param_type != 'number' && param_type != 'bigint') {
210
+ param = param.toString();
211
+ break;
159
212
  }
160
- else {
161
- maybe_sign = '';
213
+ // Round and add suffix
214
+ if (param_type == 'number')
215
+ param = Math.round(param);
216
+ param = param.toString();
217
+ let last_2_digits = param.substring(param.length - 2);
218
+ if (last_2_digits == '11' || last_2_digits == '12' || last_2_digits == '13') {
219
+ param = param + 'th';
162
220
  }
163
- // If pretty printing is enabled and the formating calls for a prefix, add it
164
- if ($pretty === '#') {
165
- switch ($type) {
166
- case 'o':
167
- maybe_sign += "0o";
221
+ else
222
+ switch (last_2_digits[last_2_digits.length - 1]) {
223
+ case '1':
224
+ param = param + 'st';
168
225
  break;
169
- case 'x':
170
- case 'X':
171
- maybe_sign += "0x";
226
+ case '2':
227
+ param = param + 'nd';
172
228
  break;
173
- case 'b':
174
- maybe_sign += "0b";
229
+ case '3':
230
+ param = param + 'rd';
175
231
  break;
232
+ default: param = param + 'th';
176
233
  }
177
- }
178
- //pad with zeroes if specified
179
- if ($pad_zeroes === '0') {
180
- filled = true;
181
- while (param.length < width - maybe_sign.length) {
182
- param = '0' + param;
183
- }
184
- }
185
- param = maybe_sign + param;
186
- }
187
- if (!filled && width > true_length) {
188
- // Compute fill/align
189
- $align_direction ||= '>';
190
- $fill_character ||= ' ';
191
- let left = '';
192
- let right = '';
193
- let diff = width - true_length;
194
- switch ($align_direction) {
195
- case '>':
196
- left = $fill_character.repeat(diff);
234
+ if (format.type == 'N')
235
+ param = param.toUpperCase();
236
+ // Do not pad with zeroes or align to precision when using ordinal formatting
237
+ format.pad_zeroes = false;
238
+ format.precision = -1;
239
+ break;
240
+ case '?':
241
+ true_length = node_util_1.default.inspect(param, {
242
+ depth: Infinity,
243
+ colors: false,
244
+ compact: !format.pretty
245
+ }).length;
246
+ param = node_util_1.default.inspect(param, {
247
+ depth: Infinity,
248
+ colors: debugColors,
249
+ compact: !format.pretty
250
+ });
251
+ // Do not force sign, pad with zeroes or align to precision when using debug formatting
252
+ param_type = 'string';
253
+ break;
254
+ default:
255
+ param = param.toString();
256
+ break;
257
+ }
258
+ ;
259
+ if (true_length == -1) {
260
+ true_length = param.length;
261
+ }
262
+ // Compute radix-point precision on numbers
263
+ if (param_type == 'number' && format.precision != -1) {
264
+ let [pre, post] = param.split('.');
265
+ if (!format.precision) { // precision = 0, do not include radix point
266
+ param = pre;
267
+ }
268
+ else {
269
+ post = ((post || '') + '0'.repeat(format.precision)).slice(0, format.precision);
270
+ param = pre + '.' + post;
271
+ }
272
+ // Update true length for fill/align
273
+ true_length = param.length;
274
+ }
275
+ let filled = false;
276
+ if ((param_type == 'number') || (param_type == 'bigint')) {
277
+ // Compute parameter sign
278
+ let maybe_sign = param.substring(0, 1);
279
+ if (maybe_sign === '-') {
280
+ param = param.substring(1, param.length);
281
+ }
282
+ else if (format.force_sign == '+') {
283
+ maybe_sign = '+';
284
+ }
285
+ else if (format.force_sign == '-') {
286
+ maybe_sign = ' ';
287
+ }
288
+ else {
289
+ maybe_sign = '';
290
+ }
291
+ // If pretty printing is enabled and the formating calls for a prefix, add it
292
+ if (format.pretty) {
293
+ switch (format.type) {
294
+ case 'o':
295
+ maybe_sign += '0o';
197
296
  break;
198
- case '<':
199
- right = $fill_character.repeat(diff);
297
+ case 'x':
298
+ case 'X':
299
+ maybe_sign += '0x';
200
300
  break;
201
- case '^':
202
- left = $fill_character.repeat(diff - diff / 2);
203
- // Prioritise right-aligment on uneven length
204
- right = $fill_character.repeat(diff / 2 + diff % 2);
301
+ case 'b':
302
+ maybe_sign += '0b';
205
303
  break;
206
304
  }
207
- param = left + param + right;
208
305
  }
209
- return param;
210
- });
211
- return str;
306
+ //pad with zeroes if specified
307
+ if (format.pad_zeroes) {
308
+ filled = true;
309
+ while (param.length < format.width - maybe_sign.length) {
310
+ param = '0' + param;
311
+ true_length++;
312
+ }
313
+ }
314
+ true_length += maybe_sign.length;
315
+ param = maybe_sign + param;
316
+ }
317
+ if (!filled && format.width > true_length) {
318
+ // Compute fill/align
319
+ let left = '';
320
+ let right = '';
321
+ let diff = format.width - true_length;
322
+ switch (format.align) {
323
+ case '>':
324
+ left = format.fill.repeat(diff);
325
+ break;
326
+ case '<':
327
+ right = format.fill.repeat(diff);
328
+ break;
329
+ case '^':
330
+ left = format.fill.repeat(diff - diff / 2);
331
+ // Prioritise right-aligment on uneven length
332
+ right = format.fill.repeat(diff / 2 + diff % 2);
333
+ break;
334
+ }
335
+ param = left + param + right;
336
+ }
337
+ return param;
212
338
  }
339
+ exports.formatParam = formatParam;
package/lib/index.d.ts CHANGED
@@ -1,2 +1,15 @@
1
- export { format } from './format';
1
+ import { RsString } from './format';
2
2
  export { print, println, eprint, eprintln } from './print';
3
+ /**
4
+ * Tag to use Rust-style formatting in a template literal.
5
+ * Returns an extended `String` object.
6
+ *
7
+ * @returns a String object with the formatted string
8
+ */
9
+ export declare function rs(strings: TemplateStringsArray, ...params: any[]): RsString;
10
+ export declare namespace rs {
11
+ var raw: (strings: TemplateStringsArray, ...params: any[]) => string;
12
+ var ref: (n: number) => {
13
+ __rs_param_ref: number;
14
+ };
15
+ }
package/lib/index.js CHANGED
@@ -1,10 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.eprintln = exports.eprint = exports.println = exports.print = exports.format = void 0;
4
- var format_1 = require("./format");
5
- Object.defineProperty(exports, "format", { enumerable: true, get: function () { return format_1.format; } });
3
+ exports.rs = exports.eprintln = exports.eprint = exports.println = exports.print = void 0;
4
+ const format_1 = require("./format");
6
5
  var print_1 = require("./print");
7
6
  Object.defineProperty(exports, "print", { enumerable: true, get: function () { return print_1.print; } });
8
7
  Object.defineProperty(exports, "println", { enumerable: true, get: function () { return print_1.println; } });
9
8
  Object.defineProperty(exports, "eprint", { enumerable: true, get: function () { return print_1.eprint; } });
10
9
  Object.defineProperty(exports, "eprintln", { enumerable: true, get: function () { return print_1.eprintln; } });
10
+ /**
11
+ * Tag to use Rust-style formatting in a template literal.
12
+ * Returns an extended `String` object.
13
+ *
14
+ * @returns a String object with the formatted string
15
+ */
16
+ function rs(strings, ...params) {
17
+ return new format_1.RsString(strings, params);
18
+ }
19
+ exports.rs = rs;
20
+ /**
21
+ * Tag to use Rust-style formatting in a template literal.
22
+ * Returns a `string` primitive.
23
+ *
24
+ * @returns a string primitive of the formatted string
25
+ */
26
+ rs.raw = function (strings, ...params) {
27
+ return (0, format_1.buildString)(strings, params);
28
+ };
29
+ /**
30
+ * Reference another parameter in a `rs`-tagged template.
31
+ *
32
+ * @param n Number of parameter to reference
33
+ * @returns A reference to the `n`th parameter
34
+ */
35
+ rs.ref = (n) => ({ __rs_param_ref: n });
package/lib/print.d.ts CHANGED
@@ -1,74 +1,41 @@
1
+ /// <reference types="node" />
1
2
  import { Writable } from 'node:stream';
2
3
  /**
3
- * Create format printer functions with custom output/error streams.
4
+ * Print a string (or instance of String/RsString) to a stream.
4
5
  *
5
- * @param outStream Output stream (used by print and println - process.stdout by default)
6
- * @param errStream Error stream (used by eprint and eprintln - process.stderr by default)
7
- * @param options Options for the printer functions (Whether to color the debug formatting in the output - true by default)
6
+ * @param stream Stream to print the string to
7
+ * @param string String to print
8
+ * @param newline Whether to append a newline after the string
9
+ * @param colored Whether to use colors for `rs` debug formatting
10
+ */
11
+ export declare function printToStream(stream: Writable, string: string | String, newline?: boolean, colored?: boolean): void;
12
+ /**
13
+ * Print a string to stdout.
8
14
  *
9
- * @returns an object with print, println, eprint and eprintln functions that print to the specified streams
15
+ * @param string String to print
10
16
  */
11
- export declare function Printer(outStream?: Writable, errStream?: Writable, options?: {
12
- debugColors: boolean;
13
- }): {
14
- /**
15
- * Print a format string to an output stream (usually process.stdout).
16
- *
17
- * @param format_string String used for formatting
18
- * @param params Parameters to be inserted into the format string
19
- */
20
- print: (format_string: string, ...params: any[]) => void;
21
- /**
22
- * Print a format string to an output stream (usually process.stdout)
23
- * and append a newline.
24
- *
25
- * @param format_string String used for formatting
26
- * @param params Parameters to be inserted into the format string
27
- */
28
- println: (format_string: string, ...params: any[]) => void;
29
- /**
30
- * Print a format string to an error stream (usually process.stderr).
31
- *
32
- * @param format_string String used for formatting
33
- * @param params Parameters to be inserted into the format string
34
- */
35
- eprint: (format_string: string, ...params: any[]) => void;
36
- /**
37
- * Print a format string to an error stream (usually process.stderr)
38
- * and append a newline.
39
- *
40
- * @param format_string String used for formatting
41
- * @param params Parameters to be inserted into the format string
42
- */
43
- eprintln: (format_string: string, ...params: any[]) => void;
44
- };
17
+ export declare function print(string: string | String): void;
45
18
  /**
46
- * Print a format string to process.stdout.
19
+ * Print a string to stdout and append a newline.
47
20
  *
48
- * @param format_string String used for formatting
49
- * @param params Parameters to be inserted into the format string
21
+ * @param string String to print
50
22
  */
51
- export declare const print: (format_string: string, ...params: any[]) => void;
23
+ export declare function println(string: string | String): void;
52
24
  /**
53
- * Print a format string to process.stdout
54
- * and append a newline.
25
+ * Print a string to stderr.
55
26
  *
56
- * @param format_string String used for formatting
57
- * @param params Parameters to be inserted into the format string
27
+ * @param string String to print
58
28
  */
59
- export declare const println: (format_string: string, ...params: any[]) => void;
29
+ export declare function eprint(string: string | String): void;
60
30
  /**
61
- * Print a format string to process.stderr.
31
+ * Print a string to stderr and append a newline.
62
32
  *
63
- * @param format_string String used for formatting
64
- * @param params Parameters to be inserted into the format string
33
+ * @param string String to print
65
34
  */
66
- export declare const eprint: (format_string: string, ...params: any[]) => void;
35
+ export declare function eprintln(string: string | String): void;
67
36
  /**
68
- * Print a format string to process.stderr
69
- * and append a newline.
37
+ * Debug print a value to stderr and return it.
70
38
  *
71
- * @param format_string String used for formatting
72
- * @param params Parameters to be inserted into the format string
39
+ * @param value Value to debug print
73
40
  */
74
- export declare const eprintln: (format_string: string, ...params: any[]) => void;
41
+ export declare function dbg(value: any): any;
package/lib/print.js CHANGED
@@ -3,121 +3,75 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.eprintln = exports.eprint = exports.println = exports.print = void 0;
7
- exports.Printer = Printer;
8
- const node_process_1 = __importDefault(require("node:process"));
6
+ exports.dbg = exports.eprintln = exports.eprint = exports.println = exports.print = exports.printToStream = void 0;
9
7
  const format_1 = require("./format");
8
+ const node_process_1 = __importDefault(require("node:process"));
9
+ const _1 = require(".");
10
10
  /**
11
- * Create format printer functions with custom output/error streams.
11
+ * Print a string (or instance of String/RsString) to a stream.
12
12
  *
13
- * @param outStream Output stream (used by print and println - process.stdout by default)
14
- * @param errStream Error stream (used by eprint and eprintln - process.stderr by default)
15
- * @param options Options for the printer functions (Whether to color the debug formatting in the output - true by default)
13
+ * @param stream Stream to print the string to
14
+ * @param string String to print
15
+ * @param newline Whether to append a newline after the string
16
+ * @param colored Whether to use colors for `rs` debug formatting
17
+ */
18
+ function printToStream(stream, string, newline = false, colored = false) {
19
+ if (string instanceof format_1.RsString) {
20
+ let previousColors = string.__debugColors;
21
+ if (colored)
22
+ string.__debugColors = true;
23
+ let stringified = string.toString();
24
+ string.__debugColors = previousColors;
25
+ string = stringified;
26
+ }
27
+ if (newline)
28
+ string = string + '\n';
29
+ stream.write(string);
30
+ }
31
+ exports.printToStream = printToStream;
32
+ /**
33
+ * Print a string to stdout.
16
34
  *
17
- * @returns an object with print, println, eprint and eprintln functions that print to the specified streams
35
+ * @param string String to print
18
36
  */
19
- function Printer(outStream = node_process_1.default.stdout, errStream = node_process_1.default.stderr, options = { debugColors: true }) {
20
- return {
21
- /**
22
- * Print a format string to an output stream (usually process.stdout).
23
- *
24
- * @param format_string String used for formatting
25
- * @param params Parameters to be inserted into the format string
26
- */
27
- print: function print(format_string, ...params) {
28
- outStream.write((0, format_1.fmt_raw)(format_string, params, { colors: options.debugColors }));
29
- },
30
- /**
31
- * Print a format string to an output stream (usually process.stdout)
32
- * and append a newline.
33
- *
34
- * @param format_string String used for formatting
35
- * @param params Parameters to be inserted into the format string
36
- */
37
- println: function println(format_string, ...params) {
38
- outStream.write((0, format_1.fmt_raw)(format_string, params, { colors: options.debugColors }) + '\n');
39
- },
40
- /**
41
- * Print a format string to an error stream (usually process.stderr).
42
- *
43
- * @param format_string String used for formatting
44
- * @param params Parameters to be inserted into the format string
45
- */
46
- eprint: function eprint(format_string, ...params) {
47
- errStream.write((0, format_1.fmt_raw)(format_string, params, { colors: options.debugColors }));
48
- },
49
- /**
50
- * Print a format string to an error stream (usually process.stderr)
51
- * and append a newline.
52
- *
53
- * @param format_string String used for formatting
54
- * @param params Parameters to be inserted into the format string
55
- */
56
- eprintln: function eprintln(format_string, ...params) {
57
- errStream.write((0, format_1.fmt_raw)(format_string, params, { colors: options.debugColors }) + '\n');
58
- },
59
- };
37
+ function print(string) {
38
+ printToStream(node_process_1.default.stdout, string, false, true);
60
39
  }
61
- // export const {
62
- // /**
63
- // * Print a format string to process.stdout.
64
- // *
65
- // * @param format_string String used for formatting
66
- // * @param params Parameters to be inserted into the format string
67
- // */
68
- // print,
69
- // /**
70
- // * Print a format string to process.stdout
71
- // * and append a newline.
72
- // *
73
- // * @param format_string String used for formatting
74
- // * @param params Parameters to be inserted into the format string
75
- // */
76
- // println,
77
- // /**
78
- // * Print a format string to process.stderr.
79
- // *
80
- // * @param format_string String used for formatting
81
- // * @param params Parameters to be inserted into the format string
82
- // */
83
- // eprint,
84
- // /**
85
- // * Print a format string to process.stderr
86
- // * and append a newline.
87
- // *
88
- // * @param format_string String used for formatting
89
- // * @param params Parameters to be inserted into the format string
90
- // */
91
- // eprintln
92
- // } = Printer();
93
- const default_printer = Printer();
40
+ exports.print = print;
94
41
  /**
95
- * Print a format string to process.stdout.
42
+ * Print a string to stdout and append a newline.
96
43
  *
97
- * @param format_string String used for formatting
98
- * @param params Parameters to be inserted into the format string
44
+ * @param string String to print
99
45
  */
100
- exports.print = default_printer.print;
46
+ function println(string) {
47
+ printToStream(node_process_1.default.stdout, string, true, true);
48
+ }
49
+ exports.println = println;
101
50
  /**
102
- * Print a format string to process.stdout
103
- * and append a newline.
51
+ * Print a string to stderr.
104
52
  *
105
- * @param format_string String used for formatting
106
- * @param params Parameters to be inserted into the format string
53
+ * @param string String to print
107
54
  */
108
- exports.println = default_printer.println;
55
+ function eprint(string) {
56
+ printToStream(node_process_1.default.stderr, string, false, true);
57
+ }
58
+ exports.eprint = eprint;
109
59
  /**
110
- * Print a format string to process.stderr.
60
+ * Print a string to stderr and append a newline.
111
61
  *
112
- * @param format_string String used for formatting
113
- * @param params Parameters to be inserted into the format string
62
+ * @param string String to print
114
63
  */
115
- exports.eprint = default_printer.eprint;
64
+ function eprintln(string) {
65
+ printToStream(node_process_1.default.stderr, string, true, true);
66
+ }
67
+ exports.eprintln = eprintln;
116
68
  /**
117
- * Print a format string to process.stderr
118
- * and append a newline.
69
+ * Debug print a value to stderr and return it.
119
70
  *
120
- * @param format_string String used for formatting
121
- * @param params Parameters to be inserted into the format string
71
+ * @param value Value to debug print
122
72
  */
123
- exports.eprintln = default_printer.eprintln;
73
+ function dbg(value) {
74
+ eprintln((0, _1.rs) `${value}:?`);
75
+ return value;
76
+ }
77
+ exports.dbg = dbg;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rsformat",
3
- "version": "0.2.4",
3
+ "version": "1.0.0",
4
4
  "description": "Formatting/printing library for JavaScript that takes after rust's string formatting ",
5
5
  "files": [
6
6
  "lib",
@@ -16,10 +16,6 @@
16
16
  "default": "./lib/*.js"
17
17
  }
18
18
  },
19
- "scripts": {
20
- "build": "tsc",
21
- "test": "echo \"Error: no test specified\" && exit 1"
22
- },
23
19
  "keywords": [
24
20
  "fmt",
25
21
  "format",
@@ -36,5 +32,8 @@
36
32
  "devDependencies": {
37
33
  "@types/node": "^22.8.6"
38
34
  },
39
- "packageManager": "pnpm@9.14.2+sha512.6e2baf77d06b9362294152c851c4f278ede37ab1eba3a55fda317a4a17b209f4dbb973fb250a77abc463a341fcb1f17f17cfa24091c4eb319cda0d9b84278387"
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "test": "echo \"Error: no test specified\" && exit 1"
38
+ }
40
39
  }