Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
super-progress
Advanced tools
Super progress bar is a CLI progress bar.
It accepts a pattern string that contains tokens that represent the different fields that can be output in the progress bar.
// Default pattern string
let pb = Progress.create({
pattern: `[{spinner}] {bar} | Elapsed: {elapsed} | {percent}`
});
It also accepts a set of custom token definitions that define the various tokens in the pattern string as well as how to render each token.
// Example token definition
{
percent: {
render: (state: ProgressState, allowed: number): string => {
return (state.percentComplete * 100).toFixed(2) + '%';
},
width: () => 7
}
}
Each token is specified within the pattern string by its key, surrounded by curly braces (ex. {bar}
). If a custom token has the same key as a default token, the default token is replaced.
Each token definition is composed of three parts:
Multiple instances of the same token are allowed in the pattern string.
The progress bar rendering function uses a two-pass process to render the whole bar.
On the first pass, each token is queried for its rendered width. If a token returns a -1 instead of a width, this indicates that the token is variable-width and will use the space allotted to it by the render function.
On the second pass, all of the widths of the known-width tokens and 'literal' characters (characters that are not a part of any known token) in the pattern string are added together and subtracted from the space available in the console. The amount left over (if any) is then divided evenly across all of the tokens that returned a -1 on the first pass. Every token's render function is then called with the current state of the progress bar and the allowed width per unknown-width token as arguments. The return value of each render function is then inserted in place of the token's placeholder(s) in the pattern string.
npm i -S super-progress
import { Progress } from 'super-progress';
import { clearInterval } from 'timers';
const pb = Progress.create();
let t = setInterval(() => {
pb.update()
.then(() => pb.render(process.stdout.columns))
.then(r => pb.display(r, process.stdout))
.then(() => {
if (pb.state.percentComplete >= 1.0) {
clearInterval(t);
}
})
}, 100);
const progress = require('super-progress').Progress;
const pb = progress.create();
let t = setInterval(() => {
pb.update()
.then(() => pb.render(process.stdout.columns))
.then(r => pb.display(r, process.stdout))
.then(() => {
if (pb.state.percentComplete >= 1.0) {
clearInterval(t);
}
})
}, 100);
This can be passed to Progress.create() to customize the layout, token definitions, and capacity of the progress bar
interface ProgressOptions {
total?: number;
pattern?: string;
renderInterval?: number;
}
The capacity of the progress bar
The pattern string specifying where the tokens are to be inserted. Each token can be used as many times as needed.
For example:
'{spinner}--{spinner} {indeterminate} {bar} {indeterminate} {spinner}--{spinner}'
yields
The minimum amount of time (in ms) to wait between frames. This only applies if you use the display method provided in the Progress class.
This contains the current state of the progress bar. It can be saved and reused to restore the progress bar's state at a later time (for example, if the current process has to be interrupted).
interface ProgressState {
startTime: number;
elapsedTime: number;
remainingTime: number;
nextRender: number;
percentComplete: number;
rateTicks: number;
currentTicks: number;
totalTicks: number;
ticksLeft: number;
}
The time at which the progress bar was created, in the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
The amount of time (in ms) that has passed since the progress bar was created.
The estimated amount of time (in ms) remaining in the process.
The time at which the next render should take place. This only applies if you use the display method provided in the Progress class.
The amount of the process that has completed, as a percentage.
The rate of tick completion, calculated as ticks per millisecond.
The current number of ticks that have been completed.
The total number of ticks in the whole process (as provided to the Progress class constructor).
The total number of ticks that remain in the process.
Contains the definitions of the tokens in the progress bar.
interface ProgressTokenDefinitions {
'key': {
render: (state: ProgressState, allowed: number) => string;
width: (state: ProgressState) => number;
}
. . .
}
The string that, when surrounded by curly braces {}
and inserted into the pattern string, acts as the placeholder for the rendered content of the token.
The function that renders the token output. The current state and the space allowance are given as inputs.
This function indicates how much space the token will take up (in characters) when rendered. A return of -1 indicates that the token will take up as much space as is available to it.
Main class that represents the progress bar
export class Progress {
public static create(options?: ProgressOptions, tokens?: ProgressTokenDefinitions, state?: ProgressState): Progress
public async display(rendered: string[], stream: Writable): Promise<void>
public async update(ticks: number = 1): Promise<void>
public async render(width: number): Promise<string[]>
}
Creates a new Progress object using the specified parameters.
Default parameters:
options = {
total: 100,
pattern: `[{spinner}] {bar} | Elapsed: {elapsed} | {percent}`,
renderInterval: 33
}
tokens = {
// the bar token displays a bar showing how much of a process has
// completed. It takes up as much space as the layout engine will
// allow. This is specified by returning -1 in the width function.
bar: {/*...*/},
// the elapsed token displays the amount time that has elapsed since
// the beginning of the process. It is displayed in hh:mm:ss.sss format.
// Since we know the exact width of the desired output, we return it
// in the width function.
elapsed: {/*...*/},
// the percent token displays the amount of the process that has been
// completed as a percentage. It shows 2 decimal places of precision.
percent: {/*...*/},
// The spinner token simply displays an ascii 'wheel' that constantly
// spins as the process is occurring.
spinner: {/*...*/}
}
state = {
elapsedTime: 0,
remainingTime: 0,
percentComplete: 0,
currentTicks: 0,
rateTicks: 0,
nextRender: 0,
startTime: Date.now(),
totalTicks: 100, // or the value supplied in options, if supplied
ticksLeft: 100, // or the value supplied in options, if supplied
}
Displays the strings in rendered on the provided stream. Each entry in the array represents a line. This function joins the array with os.EOL, writes it to the stream and repositions the cursor to the beginning of the line on which it started.
Updates the state of the progress bar by the specified number of ticks.
Renders the progress bar in its current state. The width specifies how many characters are available on each line.
FAQs
Cli progress bar that features extreme customizability
We found that super-progress demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.