npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

rsformat

v0.2.0

Published

Formatting/printing library for JavaScript that takes after rust's string formatting

Downloads

166

Readme

RSFormat

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.

Motivation

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.

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.

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.

Usage

you can install rsformat using npm:

npm install rsformat

Basic formatting and printing to console

RSFormat functions are called using a format string, and any number of format arguments following it.

Any instance of {} in the format strings will get replaced with a value.

You can specify what value you want in the parameters by using a number inside the insertion point.

import { format, println } from 'rsformat';      // ESM
const { format, println } = require('rsformat'); // CommonJS

let name = 'everyone';

let greeting = format('Hello {}!', name); // Evaluates to the string 'Hello, everyone!'

println('I have {1} apples and {0} oranges', 13, 14); // Will print 'I have 14 apples and 13 oranges' to the console

Format Specifiers

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 for more detailed information on format specifiers.

This implementation differs from the rust one in a few ways:

  • Named arguments before or in format specifiers or in values aren't allowed, only numbers can be used.
  • The - sign (unused in rust) is unsupported.
  • Pointer format type p is unsupported.
  • Hexadecimal debug types x? and X? are unsupported.
  • Specifying precision with * is unsupported.

Different formatting types

// Debug format specifier: ?, uses util.inspect rather than toString

println('{}', { a: 1 }); //prints '[object Object]'
println('{:?}', { a: 1 }); //prints "{ a:1 }"

// Number base specifiers: x, X, b, o - for lower/uppercase hexadecimal, binary, octal

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'

// Scientific notation specifiers: e, E - for lower/uppercase scientific notation

let hugeNumber = 1000n;
format('{:E}', hugeNumber); // '1E3';

Padding, Alignment

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:

/*
Will print a pyramid of 'a's:
'  a  '
' aaa '
'aaaaa'
*/
let pyramidLevels = ['a', 'aaa', 'aaaaa'];
for(let value of pyramidLevels) {
    println('{:^5}', value);
}
format('{:.>7}', [1,2]); // '....1,2'

Pretty Printing

In some instances (namely debug 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 0x to hexadecimal numbers.

format('{:#X}', 255); // '0xFF'

Specific Number Formatting

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.

format('{:#07x}', 15) // '0x0000F'

Decimal precision can be specified for numbers by adding a . and specifying an integer for precision.

format('{:.3}', 1.23456789); // '1.234'
format('{:.3}', -1);         // '-1.000'

Adding a + to the formatting specifier will print the sign regardless of whether the number is negative.

format('{:+}', 1); // '+1'

Custom output

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.

// Custom output example (ts)
import { Printer } from 'rsformat/print';
import { Writable } from 'stream';

let someOutputStream: Writable = /* ... */;
let someErrorStream: Writable = /* ... */;

let { print, println, eprint, eprintln } = Printer(someOutputStream, someErrorStream);

A Note on Performance

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.

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:

// benchmark.mjs
import { println } from 'rsformat';

const time = (fn, iter) => {
    let time = Date.now();
    while (iter-- > 0) {
        fn();
    }
    return Date.now() - time;
}

let iterations = 100000;

let logTime = time(() => console.log('hello'), iterations);
let printlnTime = time(() => println('{:>+#7X}', 255), iterations);

println('console.log time for {} executions: {}ms', iterations, logTime);
println('rsformat.println time for {} executions: {}ms', iterations, printlnTime);
> node benchmark.mjs
...After a lot of output...

console.log time for 100000 executions: 7217ms
rsformat.println time for 100000 executions: 5900ms

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.