rsformat 1.2.1 → 1.3.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 +173 -162
- package/docs.md +29 -0
- package/lib/format.js +4 -0
- package/lib/print.js +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,163 +1,174 @@
|
|
|
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
|
-
|
|
35
|
-
To reference a previous or following argument, use `rs.ref` with the argument number. This is useful if you want to reuse a complicated expression without having to declare it separately.
|
|
36
|
-
|
|
37
|
-
```js
|
|
38
|
-
import { rs, println } from 'rsformat'; // ESM
|
|
39
|
-
const { rs, println } = require('rsformat'); // CommonJS
|
|
40
|
-
|
|
41
|
-
let number = 14;
|
|
42
|
-
|
|
43
|
-
let info = rs`${number+1} is ${rs.ref(0)}:x in hex`; // info == '15 is f in hex'
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
> 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`.
|
|
47
|
-
|
|
48
|
-
The printing functions can be called with plain strings, instances of `String` or templates formatted with `rs`:
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
println('Hello World');
|
|
52
|
-
println(`This template did ${'Not'} need fancy formatting`);
|
|
53
|
-
println(rs`...`);
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Format Specifiers
|
|
57
|
-
|
|
58
|
-
Format specifiers can be used by adding `:` after the format argument, and will format the value differently inside the string. See
|
|
59
|
-
|
|
60
|
-
This implementation differs from the Rust one in a few ways:
|
|
61
|
-
|
|
62
|
-
- Rather than escaping the braces using `{{` or `}}`, the formatting colon can be escaped using `::`.
|
|
63
|
-
- Different parameters are referenced using `rs.ref(n)` rather than the number literal `n`.
|
|
64
|
-
- 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 `:#?`)
|
|
65
|
-
- The `-` sign (unused in Rust) will add a space if the number is positive to align it with negative numbers without showing a `+`.
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
- `
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
println(rs`${obj}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
- `
|
|
88
|
-
- `
|
|
89
|
-
- `
|
|
90
|
-
- `
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
let
|
|
99
|
-
let
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
'
|
|
110
|
-
'
|
|
111
|
-
'
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
rs`${
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Adding a
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
rs`${1}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
+
|
|
35
|
+
To reference a previous or following argument, use `rs.ref` with the argument number. This is useful if you want to reuse a complicated expression without having to declare it separately.
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
import { rs, println } from 'rsformat'; // ESM
|
|
39
|
+
const { rs, println } = require('rsformat'); // CommonJS
|
|
40
|
+
|
|
41
|
+
let number = 14;
|
|
42
|
+
|
|
43
|
+
let info = rs`${number+1} is ${rs.ref(0)}:x in hex`; // info == '15 is f in hex'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
> 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`.
|
|
47
|
+
|
|
48
|
+
The printing functions can be called with plain strings, instances of `String` or templates formatted with `rs`:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
println('Hello World');
|
|
52
|
+
println(`This template did ${'Not'} need fancy formatting`);
|
|
53
|
+
println(rs`...`);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Format Specifiers
|
|
57
|
+
|
|
58
|
+
Format specifiers can be used by adding a `:` after the format argument, and will format the value differently inside the string. See `docs.md` for more detailed information on format specifiers.
|
|
59
|
+
|
|
60
|
+
This implementation differs from the Rust one in a few ways:
|
|
61
|
+
|
|
62
|
+
- Rather than escaping the braces using `{{` or `}}`, the formatting colon can be escaped using `::`.
|
|
63
|
+
- Different parameters are referenced using `rs.ref(n)` rather than the number literal `n`.
|
|
64
|
+
- 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 `:#?`)
|
|
65
|
+
- The `-` sign (unused in Rust) will add a space if the number is positive to align it with negative numbers without showing a `+`.
|
|
66
|
+
- When used on strings, `+` and `-` sign specifiers will conver them to uppercase and lowercase respectively
|
|
67
|
+
- Pointer format type `p` is unsupported.
|
|
68
|
+
- Hexadecimal debug types `x?` and `X?` are unsupported.
|
|
69
|
+
- 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.
|
|
70
|
+
- New format types have been added:
|
|
71
|
+
- `N` for uppercase ordinal suffixing of numbers (rounded to integers)
|
|
72
|
+
- `n` for lowercase ordinal suffixing of numbers (rounded to integers)
|
|
73
|
+
|
|
74
|
+
#### Different formatting types
|
|
75
|
+
|
|
76
|
+
The debug format specifier `?` uses `util.inspect` to stringify the parameter rather than `toString`.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
let obj = { a: 1 };
|
|
80
|
+
println(rs`${obj}`); // prints '[object Object]'
|
|
81
|
+
println(rs`${obj}:?`); // prints '{ a: 1 }'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The provided printing functions will display colors in the output of `util.inspect`, but otherwise it will be formatted without color.
|
|
85
|
+
|
|
86
|
+
The specifiers `b`,`o`,`x`,`X`,`e`,`E`,`n`,`N` will convert a `number` or `bigint` parameter to:
|
|
87
|
+
- `b`: binary
|
|
88
|
+
- `o`: octal
|
|
89
|
+
- `x`/`X`: lowercase/uppercase hexadecimal
|
|
90
|
+
- `e`/`E`: lowercase/uppercase scientific notation
|
|
91
|
+
- `n`/`N`: lowercase/uppercase ordinal suffixed string (rounded to integer)
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
let advancedInfo = (n) => rs`${n} is ${n}:x in hex, ${n}:b in binary and ${n}:o in octal`;
|
|
95
|
+
|
|
96
|
+
advancedInfo(15); // '15 is f in hex, 1111 in binary and 17 in octal'
|
|
97
|
+
|
|
98
|
+
let hugeNumber = 1000n;
|
|
99
|
+
let science = rs`${hugeNumber}:E`; // '1E3'
|
|
100
|
+
let ordinal = rs`${hugeNumber}:n`; // '1000th'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Padding, Alignment
|
|
104
|
+
|
|
105
|
+
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.
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
/*
|
|
109
|
+
Will print a pyramid of 'a's:
|
|
110
|
+
' a '
|
|
111
|
+
' aaa '
|
|
112
|
+
'aaaaa'
|
|
113
|
+
*/
|
|
114
|
+
let pyramidLevels = ['a', 'aaa', 'aaaaa'];
|
|
115
|
+
for(let value of pyramidLevels) {
|
|
116
|
+
println(rs`${value}:^5`);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
rs`${[1,2]}:.>${7}` // '....1,2'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Pretty Printing
|
|
125
|
+
|
|
126
|
+
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.
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
rs`${255}:#X` // '0xFF'
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### Specific Number Formatting
|
|
133
|
+
|
|
134
|
+
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.
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
rs`${15}:#07x` // '0x0000F'
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
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.
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
rs`${1.23456789}:.3` // '1.234'
|
|
144
|
+
rs`${-1}:.${3}` // '-1.000'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Adding a `+` to the formatting specifier will print the sign regardless of whether the number is negative.
|
|
148
|
+
Adding a `-` will instead add a space if the number is positive.
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
rs`${1}:+` // '+1'
|
|
152
|
+
rs`${1}:-` // ' 1'
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### String formatting
|
|
156
|
+
|
|
157
|
+
Adding a `+` or `-` to a formatting specifier of a string will instead convert it to uppercase or lowercase respectively.
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
let str = "Hello!"
|
|
161
|
+
let str_upper = rs`${str}:+` // 'HELLO!'
|
|
162
|
+
let str_lower = rs`${str}:-` // 'hello!'
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Older versions of RSFormat
|
|
166
|
+
|
|
167
|
+
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:
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
import { format } from 'rsformat';
|
|
171
|
+
format('{} is {0:#x} in hex', 15); // '15 is 0xf in hex'
|
|
172
|
+
```
|
|
173
|
+
|
|
163
174
|
See the `old` branch for more detailed documentation. The last version to use this formatting was `0.2.5`.
|
package/docs.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# rsformat Format Specifier Documentation
|
|
2
|
+
|
|
3
|
+
A rsformat format specifier is parsed as follows:
|
|
4
|
+
|
|
5
|
+
- `${value}::` Will escape the colon character and replace it with a single `:`. Stringification of `value` will occur as in normal format strings.
|
|
6
|
+
|
|
7
|
+
- `${value}:[fill][align][sign][#][0][width][.(precision)][format_type][:]` is an unescaped format specifier and will parse the string as follows:
|
|
8
|
+
|
|
9
|
+
| Name | Syntax | Purpose | Default value |
|
|
10
|
+
| ------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------- |
|
|
11
|
+
| `fill` | any single chacter | The fill character for alignment | space (` `) |
|
|
12
|
+
| `align` | `<`, `^` or `>` | The alignment direction (left, center, right) | right (`>`) |
|
|
13
|
+
| `sign` | `+` or `-` | Pad a positive number with `+` or a space ` ` (or convert a string to uppercase/lowercase) | None |
|
|
14
|
+
| `#` | `#` | Pretty printing (Add prefixes `0b`, `0o` and `0x` to binary, octal and hex-formatted numbers, and use non-compact debug formatting) | None |
|
|
15
|
+
| `0` | `0` | Pads numbers with `0` characters instead of using fill/align | None |
|
|
16
|
+
| `width` | any positive integer | Minimum width for fill/alignment | 0 |
|
|
17
|
+
| `precision` | `.` + any positive integer | Minimum precision for non-integer numbers | 0 |
|
|
18
|
+
| `format_type` | `?`,`o`,`x`,`X`,`b`,`e`,`E`,`n` or `N` | Format type (see "Different Formatting Types" in README.md) | None |
|
|
19
|
+
| `:` | `:` | Add to the end of a format specifier to not have to insert a space after it | None |
|
|
20
|
+
|
|
21
|
+
Every single one of the above values is optional, but must be included in that order.
|
|
22
|
+
|
|
23
|
+
## Examples
|
|
24
|
+
|
|
25
|
+
`${"abc"}:+:!` Will capitalise `"abc"` with an exclamation mark right after it, ie. `ABC!`
|
|
26
|
+
|
|
27
|
+
`${15}:#08x` Will convert `15` to hexadecimal, add `0x` and pad it with 0s until it is 8 characters wide, ie. `0x00000F`
|
|
28
|
+
|
|
29
|
+
`${1.2345678}:,^10.${3}` will round `1.2345678` to 3 decimal places and center align it with `,` untill it is 10 characters wide, ie. `,,1.234,,,`
|
package/lib/format.js
CHANGED
|
@@ -249,12 +249,16 @@ function formatParam(param, format) {
|
|
|
249
249
|
param = node_util_1.default.stripVTControlCharacters(param_colored);
|
|
250
250
|
// Do not force sign, pad with zeroes or align to precision when using debug formatting
|
|
251
251
|
param_type = 'string';
|
|
252
|
+
format.force_sign = '';
|
|
252
253
|
break;
|
|
253
254
|
default:
|
|
254
255
|
param = param.toString();
|
|
255
256
|
break;
|
|
256
257
|
}
|
|
257
258
|
;
|
|
259
|
+
if (param_type == 'string' && format.force_sign != '') {
|
|
260
|
+
param = format.force_sign == '+' ? param.toUpperCase() : param.toLowercase();
|
|
261
|
+
}
|
|
258
262
|
// Compute radix-point precision on numbers
|
|
259
263
|
if (param_type == 'number' && format.precision != -1) {
|
|
260
264
|
let [pre, post] = param.split('.');
|
package/lib/print.js
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rsformat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Formatting/printing library for JavaScript that takes after rust's string formatting ",
|
|
5
5
|
"files": [
|
|
6
6
|
"lib",
|
|
7
|
-
"README.
|
|
7
|
+
"README.md",
|
|
8
|
+
"docs.md"
|
|
8
9
|
],
|
|
9
10
|
"exports": {
|
|
10
11
|
".": {
|