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 🙏

© 2026 – Pkg Stats / Ryan Hefner

firost

v5.5.1

Published

Async glob, read and write files

Downloads

4,824

Readme

> firost

Async glob, read and write files.

I was getting tired of having to write the same helpers and wrappers for reading/writing files, so I packaged the best libraries and made an API that works well with async/await.

Filesystem methods

These methods help in finding, reading, moving and writing files on disk.

absolute(filepath)

Converts any filepath to an absolute path, resolving ~/ to home.

absolute('../path/to/file/oops/../.') // /absolute/path/to/file
absolute('~/.npmrc') // /home/tim/.npmrc

copy(source, destination)

Copy file(s)

await copy('index.html', './dist/index.html');
await copy('./foo/*.html', './dist');

download(url, path)

Download a file to specific path on disk

await download('http://www.example.com/file.jpg', './example.jpg');

emptyDir(path)

Empty the content of a directory

await emptyDir('./foo/bar');

exists(path)

Check if a file/directory exists

await exists('./foo/bar/file.ext');

gitRoot()

Returns the path of the closest directory holding a .git folder.

gitRoot(); // /home/tim/projects/firost
gitRoot('~/projects/aberlaas/lib/main.js'); // /home/tim/projects/aberlaas/

glob(pattern, options = {})

Returns an array of filepaths matching the specified glob pattern.

It will return hidden files and directories by default, but you can override it by passing hiddenFiles: false or directories: false to the options argument.

const paths = await glob(['./src/**/*.css', '!./src/**/_*.css']);
const noHiddenFiles = await glob(['./lib/**/*.js'], {
  hiddenFiles: false,
});
const noDirectories = await glob(['./lib'], { directories: false });

isDirectory(path)

Checks if the given path is a directory

if (await isDirectory('./dist')) {
  console.info('Website created');
}

isFile(path)

Checks if the given path is a file

if (await isFile('./package.json')) {
  console.info('File exists');
}

mkdirp(path)

Creates a set of nested directories if they don't yet exist.

await mkdirp('./dist/css');

move(source, destination)

Move file(s)

await move('index.html', 'index.back.html');
await move('./*.html', './dist');

packageRoot()

Returns the path of the closest directory holding a package.json file.

packageRoot(); // /home/tim/projects/firost
packageRoot('~/projects/aberlaas/lib/main.js'); // /home/tim/projects/aberlaas/

read(path)

Returns the textual content of a file located at the specified filepath.

const content = await read('./src/css/style.css');

readJson(path)

Returns the content of a JSON file as a JavaScript object.

const data = await readJson('./records.json');

readJsonUrl(url)

Returns the content of a JSON URL as a JavaScript object.

const data = await readJsonUrl('http://www.example.com/data.json');

remove(target)

Remove file(s)

await remove('index.back.html');
await remove('*.back.html');

urlToFilepath(url)

Converts an URL into a filepath suitable for writing the file to disk.

const filepath = urlToFilepath(
  'http://www.example.com/path/file.html?foo=bar'
);
// http/www.example.com/path/file_foo-bar.html

// Also works with relative utls
const filepath = urlToFilepath('path/file.html?foo=bar');
// path/file_foo-bar.html

watch(pattern, callback, {watcherName})

Watch for file change, and run specified callback with path to changed files.

function doSomething(filepath, type) {
  console.info(`File ${filepath} was just ${type}`);
}
const watcher = await watch(
  './path/to/files/*.jpg',
  doSomething,
  'my-watcher'
);

// To remove the watcher:
await unwatch('my-watch');
// or await unwatch(watcher);
// To remove all watchers:
await unwatchAll();
// To force wait until all watchers are executed
await waitForWatchers();

write(content, destination)

Write content to a file on disk.

await write('This is my content', './dist/content.txt');

writeJson(data, destination)

Write data to a JSON file on disk. Keys will be ordered alphabetically, for easier diffing of the file.

const records = [
  { name: 'foo', value: 2 },
  { value: 3, name: 'bar' },
];
await writeJson(records, './records/records.json');

Shell methods

These methods help abstracting some common CLI tasks

exit

Stop the current process with specified exitCode. Similar to process.exit.

exit(1);

consoleInfo

Display an information message

consoleInfo('Info');
// • Info

consoleWarn

Display a warning message

consoleWarn('Warning');
// ⚠ Warning

consoleError

Display an error message

consoleInfo('Error');
// ✘ Error

consoleSuccess

Display an success message

consoleSuccess('Success');
// ✔ Success

prompt(question)

Interactively ask user a question

const mood = await prompt('How do you feel?');

run(command)

Run a shell command just like in the terminal, but also allows access to stdout, stderr and exit code.

Options

| name | default value | description | | -------- | ------------- | ------------------------------------------------------------------------------------------- | | shell | false | Set to true to enable shell-specific feature (like &&, >, etc) | | stdout | true | Set to false to silence stdout | | stderr | true | Set to false to silence stderr | | stdin | false | Set to true to allow user to input keyboard keys. This sets stdout and stderr to true |

const { stdout } = await run('echo foo'); // foo
const { stderr } = await run('>&2 echo bar', { shell: true }); // foo
try {
  await run('echo foo && exit 42');
} catch (err) {
  // err.code = 42
  // err.stdout = foo
}

spinner(max)

Creates a spinner with optional max number of elements.

const progress = spinner(10);

progress.tick('Doing task 1');
progress.success('All tasks done');
// or progress.failure('All tasks failed');

shell(command)

Deprecated. Use run instead, it if much more flexible

Run the given command in a shell. Returns stdout, throws with stderr and exitCode.

try {
  const result = await shell('git checkout -b master');
  console.info('Created branch master');
} catch (err) {
  console.error(err.message);
  console.error(err.code);
}

sleep(delay)

Wait for a specific number of milliseconds

await sleep(100); // Wait for 100 ms

tmpDirectory()

Returns a random temporary folder, optionally scoped.

tmpDirectory(); // /tmp/{some-random-uuid}
tmpDirectory('firost/scope/'); // /tmp/firost/scope/{some-random-uuid}

which(command)

Returns the path to an executable on the system. Returns false if none is found.

if (!(await which('convert'))) {
  console.info('You need to install ImageMagick');
}

Utils

cache

Shared singleton to used a proxy cache.

cache.write('foo', 42);
cache.read('foo'); // 42
cache.has('foo'); // true
cache.has('nope'); // false

cache.write('key', { foo: ['one', 'two'], bar: { three: 3 } });
cache.read('key.foo'); // ['one', 'two'];
cache.read('key.bar.three'); // 3

cache.clear('key.foo');
cache.has('key.foo'); // false

cache.clearAll();
cache.has('key'); // false

captureOutput

Silence all output of the specified code, and return it instead

const actual = await captureOutput(async () => {
  console.info("This will not get displayed");
  await run('echo Test');
  await run('./no-existing-script.sh');
});
// actual.stdout: ["This will not get displayed", "Test"]
// actual.stderr: ["Command does not exist"]

error

Returns an Error with both a .code and a .message

throw error('E_ERROR', 'This failed');

normalizeUrl

Normalize a URL

normalizeUrl('http://www.there.com/index.html?sort=asc&name=firost');
// http://www.there.com/?name=firost&sort=asc

pulse

Shared event emitter to listen and emit events

pulse.on('custom', data => {
  console.info(data);
});
pulse.emit('custom', 'Hello');
// Hello

firostImpot(id)

Alternative to the default dynamic import(). Pass forceReload: true as an option to force reloading the latest version on disk, bypassing the singleton cache.

const module = await firostImport('./path/to/module.js');
const updatedModule = await firostImport('./path/to/module.js', {
  forceReload: true,
});

uuid()

Returns a unique ID that could be used in URL of filepaths.

console.info(uuid());
// V1StGXR8_Z5jdHi6B-myT