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 🙏

© 2025 – Pkg Stats / Ryan Hefner

dotfiler

v0.2.4

Published

everything in the right place

Readme

dotfiler

gifs and badges

Install

$ npm install -g dotfiler

What it does

Tries to free you from maintaining scripts that symlinks stuff around. All from a config file (that it generates for you, btw).

How it works

dotfiler looks for a file called .dotfiler and tries to symlink and/or copy the src to their dest. The sources can be either files or directories. The application creates symlinks by default.

This config file can be either generated by dotfiler itself via the --generate-config/-g=path option (saves time) or you can write one yourself.

When your config file is ready, you can run the application passing the directory of the project (or projects. Can be multiple) or simply calling it without arguments if you are inside the project.

# you can call dotfiler with absolute paths
dotfiler /home/node/project

# with relative paths
dotfiler ./project

# multiple relative paths also (you can run it in multiple projects)
dotfiler ./project1 ./project2 ./project3 ./projectn

# or without arguments (assumes you are inside the project directory)
dotfiler

When the run is finished, it presents you with a summary of the operations performed by it that looks a bit like this:

[CREATED]
copy - /home/node/dotfiler-dev/projects/maroon-unbranded-rubber-bike-5998370-dest/andorra_indigo_borders/
copy - /home/node/dotfiler-dev/projects/olive-ergonomic-granite-cheese-763b809-dest/frozen_card_cambridgeshire/
symlink - /home/node/dotfiler-dev/projects/red-licensed-fresh-cheese-369498b-dest/.24_365.les
symlink - /home/node/dotfiler-dev/projects/red-licensed-fresh-cheese-369498b-dest/backing/
symlink - /home/node/dotfiler-dev/projects/maroon-unbranded-rubber-bike-5998370-dest/synthesize/

[PRESENT]
copy - /home/node/dotfiler-dev/projects/red-licensed-fresh-cheese-369498b-dest/.communications_representative.chrt
copy - /home/node/dotfiler-dev/projects/red-licensed-fresh-cheese-369498b-dest/.soft_exe_shirt/
symlink - /home/node/dotfiler-dev/projects/maroon-sleek-wooden-shoes-5376726-dest/chair_borders/

[FAILED]
copy - /home/node/dotfiler-dev/projects/maroon-unbranded-rubber-bike-5998370-dest/deposit/
Could not copy /home/node/dotfiler-dev/projects/maroon-unbranded-rubber-bike-5998370/deposit/: EACCES: permission denied, scandir '/home/node/dotfiler-dev/projects/maroon-unbranded-rubber-bike-5998370/deposit/'
copy - /home/node/dotfiler-dev/projects/olive-ergonomic-granite-cheese-763b809-dest/.lane
copy - /home/node/dotfiler-dev/projects/yellow-licensed-frozen-ball-b7cd9d0-dest/hacking/
Could not copy /home/node/dotfiler-dev/projects/yellow-licensed-frozen-ball-b7cd9d0/hacking/: EACCES: permission denied, scandir '/home/node/dotfiler-dev/projects/yellow-licensed-frozen-ball-b7cd9d0/hacking/'
copy - /home/node/dotfiler-dev/projects/cyan-awesome-granite-chips-901402a-dest/money_plastic_checking/
Could not copy /home/node/dotfiler-dev/projects/cyan-awesome-granite-chips-901402a/money_plastic_checking/: EACCES: permission denied, scandir '/home/node/dotfiler-dev/projects/cyan-awesome-granite-chips-901402a/money_plastic_checking/'

[PROJECT ERRORS]
Could not read the .dotfiler config from the following project: /home/node/dotfiler-dev/projects. Reason: ENOENT: no such file or directory, open '/home/node/dotfiler-dev/projects/mint' [ENOENT]
Could not read the .dotfiler config from the following project: . Reason: ENOENT: no such file or directory, open 'green-rustic-wooden-fish-76d4dd0' [ENOENT]
Could not read the .dotfiler config from the following project: /home/node/dotfiler-dev/projects. Reason: ENOENT: no such file or directory, open '/home/node/dotfiler-dev/projects/sky' [ENOENT]
Could not read the .dotfiler config from the following project: . Reason: ENOENT: no such file or directory, open 'blue-small-rubber-chips-7a5bdcf' [ENOENT]

Of which:

  • [CREATED]: the operation run successfuly
  • [PRESENT]: the operation could not finish because there's already something in the dest. It does not overwrites data.
  • [FAILED]: the operation failed due to a possible permission problem or the src file does not exist anymore. Can be anything.
  • [PROJECT ERRORS]: happens when the .dotfiler file from a project itself couldn't be read.

The .dotfiler config file

The application will try to find this file to perform its job. You just have to point to the directory where it is placed at.

This file can be either YAML or JSON, depending on your preference.

Right now this file has a simple structure: a configs prop as an array where each element corresponds to a file or directory.

It should look like this as yaml:

---
configs:
- src: i3
  dest: "~/.configs/i3"
  copy: true
- src: tmux.conf
  dest: "~/.tmux.conf"
- src: .gitconfig
  dest: "~/.gitconfig"

Or like this as json:

{
  "configs": [
    {
      "src": "i3",
      "dest": "~/.config/i3",
      "copy": "true"
    },
    {
      "src": "tmux.conf",
      "dest": "~/.tmux.conf"
    },
    {
      "src": ".gitconfig",
      "dest": "~/.gitconfig"
    }
  ]
}

src

The name of your file or directory. It must not have any path delimiter before the name (like ./ or ..) as it is treated as relative to the current directory.

dest

Where the contents of src should be placed at. The path must be absolute, but it supports ~ to represent your home directory.

copy (optional)

If this property is set to true, dotfiler will try to copy the file or directory instead of creating a symlink.

The --generate-config=<path> option

If you have dozens of files inside your project, there's this option that reads the content of a directory and creates a "default" config file. The dest by default is the parent directory of your project. You can use it to kickstart your config.

# you point it to your project with an absolute path
dotfiler --generate-config=/home/node/myproject

# or a relative path
dotfiler --generate-config=./project

# or this for the current directory
dotfiler --generate-config=.

# a message like this is printed if everything is ok
dotfiler configuration generated at /path/to/.dotfiler

Next steps

Maybe I'll put an option to remove everything based on the config file, like you run dotfiler but want to revert. The application already has this functionality for the test environment, but I'm not sure about removing user data like this (bad things can happen).

Also there must be a way to select what sources the user want to act upon and not all the contents of the file. Right now it is all or nothing only.

Developing this thing (please contribute 😬)

As this application modifies the filesystem, it can be dangerous to run tests or develop stuff in your own machine. There's a Docker environment for this purpose so tests can be isolated elsewhere.

There are two services in the docker-compose from this project:

dev

Runs with nodemon and watches for changes in the codebase. Everytime you run it, new projects are created with lots of files so dotfiler can act on them.

# this is how you start the dev server. It acts like you are running `dotfiler /some/path` everytime it reloads
docker-compose up --build dev

test-watch

Runs jest and watches for changes in the codebase (including test files). This also creates and deletes stuff in the filesystem, that's why it is good to run it in a container.

# this is how you start the test server
docker-compose up --build test-watch

License

MIT