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

file-looper

v1.0.4

Published

Create a dist dir from a src dir, loop through and apply any plugins you like

Downloads

3

Readme

FileLooper

FileLooper allows you to easily build a dist (distribution) directory from a src directory of your choosing. Add plugins to run on select files to modify the file contents or name.

Why?

I couldn't really find a nice clean way to build a dist directory in my CI pipelines without hand making some version of it or including a heavy tool. I also found myself looping over the same files over and over again and wanted a way to do everything in one clean loop.

General Overview

When the FileLooper is run it will start by deleting the old dist directory (if one is specified). It will then create a new dist directory, recursively copying the src directory to do so.

Afterwards it will gather a list of every file inside of the new dist directory, look at the list of plugins you have added to your looper, and apply the plugins to each file that meet the conditions you set.

Adding a plugin is as simple as inputting a function into the .addPlugin() method of your FileLooper. A file interface is provided for you in your plugins to easily interact with each file.

Installation

npm install file-looper

Getting Started

Both import and require() are supported, so you can use either syntax:

Import:

import FileLooper from 'file-looper';

Require():

const { FileLooper } = require('file-looper');

Once you've imported / required it, FileLooper is a class, so to create a new one you simply

const looper = new FileLooper('src', 'dist');

The constructor currently takes two parameters, as shown above:

  • src directory (of type string, relative to your project)
  • dist directory (optional - of type string, relative to your project)
    • If no dist is specified then src is modified directly

FileLooper has two methods: addPlugin and run

Adding a Plugin (.addPlugin())

To add a plugin to your FileLooper, you use the addPlugin method. This method takes two parameters: plugin <function> and options <object> (optional). Here's a simple demo:

import FileLooper from 'file-looper';

const looper = new FileLooper('src', 'dist');

// Pass in the file parameter to interact with the current file in the loop
looper.addPlugin(file => {
  minifyHTML(file.dataStr);
  file.renameFile = {
    extension: '.min.html'
  };
}, {
  // You can reference this ID in .run() if you want to only run this Plugin
  id: 'html-minifier',
  // You can reference these categories later if, for example, you only want
  // to run Plugins with one (or more) of these categories
  categories: ['minify','html'],
   // only applies this plugin to .html files
  onlyDo: {
    extensions: ['html']
  }
});

As you add in your Plugins, they will all be run in the order you added them (since they are just pushed to an array, you can view this array at .plugins in your FileLooper.

Here are all of the options and configurations available to you in the addPlugin method

  • plugin <function> This is the function that will be executed when this plugin is run. Here you can modify the contents of the given file, rename it, log anything to the console, whatever you would like to do. This function has one parameter:
    • file <object> Your interface for interacting with the current file in the loop. It has the following properties for you to use:
      • ReadOnly:
        • loopNumber <number> By default the run() method only does one loop, but if you specify multiple loops this will keep track of what number loop you are on. It starts incrementing at 1.
        • fullPath <string> The absolute path of the current file
        • relativePath <string> (not implemented yet) The path of the current file relative to your project
        • fullFileName <string> The file name (with the file extension) of the current file
        • fileName <string> The file name (without the file extension) of the current file
        • extension <string> The file extension of the current file
      • Writeable:
        • dataStr <string> (optional) The contents, as a string, of the current file. The final result of your manipulation of this string will be written to the given file. By default this will be used for HTML files unless specified with the useDoc attribute.
        • document <JSDOM document> (optional) Only available if the current file is an HTML file. This is a JSDOM representation of the current file. The contents of the file was input into a JSDOM Object, and then the dom.window.document of that object was returned to you here. This provides an interface to more easily query elements and manipulate them.
        • useDoc <boolean> (optional) Set this variable to true if you would like FileLooper to ignore the dataStr property and use the document property (only applicable for HTML files). This is WriteOnly as it contains no data by default.
        • renameFile <object> (optional) An interface provided for renaming the current file. This is WriteOnly as it contains no data by default.
          • fileName <string> (optional) The name you would like to rename the current file to (do not include extension). If not specified, the same filename will be kept.
          • extension <string> (optional) The new extension you would like to give to the current file. You can add the . before hand or not, your choice.
  • options <object> (optional) This allows you to add an id and / or categories to your Plugin so you can select which Plugins you'd like to run in the run() method. This also lets you specify on which files & directories this plugin should be applied to. The allowed properties (all of which are optional):
    • id <string> (optional) A unique ID for your plugin, used by run() to filter which Plugins you'd like to run
    • categories <array of strings> (optional) Similar to id, allows you to filter which Plugins you'd like to run by giving this Plugin categories (e.g. you add the string minify to this array of categories, and then in run() you specify to onlyDo the Plugins with the minify category)
    • onlyDo <object> (optional) Allows you to only run this Plugin on the files that meet the criteria in this Object
      • fullFilePaths <array of strings or RegExp> (optional) The absolute path of any file(s) you would like to apply this plugin to
      • fullFileNames <array of strings or RegExp> (optional) The file name(s) (including the file extension) of any file you would like to apply this plugin to
      • fileNames <array of strings or RegExp> (optional) The file name(s) (excluding the file extension) of any file you would like to apply this plugin to
      • directories <array of strings or RegExp> (optional) The directory / directories of files you would like to apply this plugin to
      • extensions <array of strings or RegExp> (optional) The file extension of the file(s) you would like to apply this plugin to
    • exclude <object> (optional) The opposite of onlyDo, any file that meets the criteria in this object will not have this Plugin applied to it
      • fullFilePaths <array of strings or RegExp> (optional) The absolute path of any file(s) you would like to NOT apply this plugin to
      • fullFileNames <array of strings or RegExp> (optional) The file name(s) (including the file extension) of any file you would like to NOT apply this plugin to
      • fileNames <array of strings or RegExp> (optional) The file name(s) (excluding the file extension) of any file you would like to NOT apply this plugin to
      • directories <array of strings or RegExp> (optional) The directory / directories of files you would like to NOT apply this plugin to
      • extensions <array of strings or RegExp> (optional) The file extension of the file(s) you would like to NOT apply this plugin to

Running the FileLoop (.run())

Once you have added all of your Plugins to your FileLooper, you use the run method to execute run the FileLooper as you might expect. The run() method does not return any data, but it is asynchronous so make sure to watch out for that when calling it.

The run method takes one (optional) parameter: options <object>. Here is simple demo:

import FileLooper from 'file-looper';

const looper = new FileLooper('src', 'dist');

looper.addPlugin(file => {
  minifyHTMLPlugin(file);
}, {
  id: 'html-minifier',
  categories: ['minify','html'],
  onlyDo: {
    extensions: ['html']
  }
});

looper.addPlugin(file => {
  minifyCSSPlugin(file);
}, {
  id: 'css-minifier',
  categories: ['minify','css'],
  onlyDo: {
    extensions: ['css']
  }
});

// This will run all Plugins with the 'minify' category,
// but will exclude the Plugin that has the id 'css-minifier'
looper.run({
  onlyDo: {
    categories: ['minify']
  }
  exclude: {
    id: ['css-minifier']
  }
}).then(() => {
  console.log('FileLooper has finished running!');
});

Here are all of the options and configurations available to you in the run method (all of which are optional)

  • numLoops <number> (optional) The number of loops you would like to execute. Useful if you have Plugins that need other Plugins to apply to every file before hand. Defaults to 1 if not specified.
  • onlyDo <object> (optional) Allows you to only run the Plugins that meet the criteria in this Object
    • id <array of strings> (optional) Only the Plugins that have IDs contained in this array will be run
    • categories <array of strings> (optional) Only the Plugins that have categories contained in this array will be run. Only one category needs to match for the Plugin to run.
  • exclude <object> (optional) Allows you to exclude any Plugin from running so long as it meets the criteria of this object (the opposite of onlyDo)
    • id <array of strings> (optional) The Plugins that have IDs contained in this array will be NOT be run
    • categories <array of strings> (optional) The Plugins that have categories contained in this array will NOT be run. Only one category needs to match for the Plugin to NOT run.

Quick Note: For both run and addPlugin options, if both onlyDo and exclude are specified then only the Plugins that match both creteria will be run.

License

Licensed under ISC