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

pachyderm

v0.0.3

Published

Lazily require a directory, loading nothing until it is called

Downloads

4

Readme

pachyderm

Build a single javascript file that represents an entire directory.

Use this tool if you'd rather not do this.

var subModule = require('some-module/digging/through/directories/for/source');

If you'd rather do this,

var entireModule = require('some-module');

var subModule = entireModule.digging.through.directories.for.source;

then pachyderm might be for you.

If you look at the above example and are concerned about large projects being loaded all at once, then don't worry! Pachyderm arranges the resulting module in a way so that the resource subModule is only required when it is asked for, not when entireModule is defined.

A quick example.
Skip to Options.

When would I use it?

Let's take an example project that might benefit from pachyderm. Here, a large collection of directories and stand alone modules were created without the intent of releasing them as an npm module. Later, this changes. Instead of creating an index.js file that simply requires javascript files from deeper within the project, it'd be nice to generate it instead.

$> tree myProject
api
└── src
    ├── routes.js
    ├── auth.js
    ├── auth.spec.js
    ├── myProject
    │   ├── myProject.js
    │   └── myProject.spec.js
    └── common
        ├── README.md
        ├── util.js
        └── util.spec.js
apiSDK
└── components
    ├── preferences.js
    ├── purchaseOrders
    │   ├── add.js
    │   ├── disable.js
    │   └── history.js
    ├── purchaseOrders.js
    ├── search
    │   ├── account.js
    │   └── keyword.js
    ├── transactions.js
    ├── util.js
    └── index.js
tests
├── preferences.js
├── purchaseOrders
│   ├── add.js
│   ├── disable.js
│   └── history.js
├── purchaseOrders.js
├── search
│   ├── account.js
│   └── keyword.js
└── transactions.js

In this example, an API has been created as the main project resource, and in another directory, an API SDK has been created to abstract over it. In a final directory, there are the tests that utilize the SDK. If you split this up, you'd lose the advantage of having the project's API, SDK, and tests being featured together. As new API endpoints are added, the SDK can be updated, as well as the tests, with minimal hassle. They are all first class citizens of a singular project.

However, publishing the SDK as a node module would require that there be some sort of index.js entry point, and creating and updating this manually is tedious, and error prone. The SDK was initially written to simplify testing the API, but over time it became useful enough to the users of the API that they asked for it to become a dependency within their applications.

In this example, pachyderm would be a good fit -- the only need for the SDK is to bundle all the files in the components directory into a singular index.js file. Each one stands alone as a module, and users only need to access them individually to utilize the SDK.

Again, this is used to avoid having your SDK behave like this.

var sdk = require('api-sdk');

var sdkAccountSearch = require('api-sdk/search/account');
var sdkKeywordSearch = require('api-sdk/search/keyword');

sdkAaccountSearch('12345');
sdkKeywordSearch('foobar');

And instead, would act as a singular require statement.

var sdk = require('api-sdk');

sdk.search.account('12345');
sdk.search.keyword('foobar');

Using pachyderm, a developer would work as they normally do. Once a new endpoint is added, the SDK and tests are updated. Everything is normal. The only thing that changes is that when it comes time to release a new version of the API, the SDK can be shipped along with it. This is done by adding an .npmrc, package.json, .npmignore, etc., to the ./apiSDK directory.

Later, perhaps in some gulp/grunt task, an extra step is added to run pachyderm over the apiSDK directory.

Generating a Directory as Javascript

var pachyderm = require('pachyderm');

pachyderm.go({ directory: './apiSDK/components/' });

This would be committed as part of the current release. Finally, you'd cd into the apiSDK directory and run npm publish.

This allows the API and SDK to stay in sync in the same project, even though to the rest of the world the SDK appears to be a stand alone project.

The resulting ./apiSDK/components/index.js would look like this:

/**
 This file is auto-generated by `pachyderm`.
 https://www.npmjs.com/package/pachyderm
 */
module.exports = {
    get preferences() { return require('./preferences.js'); },
    purchaseOrders: {
        get add() { return require('./purchaseOrders/add.js'); },
        get disable() { return require('./purchaseOrders/disable.js'); },
        get history() { return require('./purchaseOrders/history.js'); }
    },
    get purchaseOrdersJs() { return require('./purchaseOrders.js'); },
    search: {
        get account() { return require('./search/account.js'); },
        get keyword() { return require('./search/keyword.js'); }
    },
    get transactions() { return require('./transactions.js'); },
    get util() { return require('./util.js'); }
};

Attentive readers will notice that the resulting javascript object had a key collision. There was a purchaseOrders.js file that matched purchaseOrders/, a directory. In this instance, the value found in the option appendToConflicts is used to differentiate between files and directories that have the same name. By default, this is 'Js'.

Options

Here are the defaults for running pachyderm without specifying anything.

pachyderm.go({
    directory: path.resolve('.'),
    output: 'index.js',
    shouldBeIndexed: function (filename) {
        return _.all([
            filename.slice(-3) === '.js',
            filename.slice(-8) !== 'index.js',
            filename.match(/node_modules/) === null
        ]);
    },
    header: [
        ' This file is auto-generated by `pachyderm`.',
        ' https://www.npmjs.com/package/pachyderm'
    ].join('\n'),
    appendToConflicts: 'Js'
});

directory

The directory to be traversed and transformed into an object.

output

The name of the resulting javascript file. It will always be the direct child of the directory that was traversed.

shouldBeIndexed

A function that will be applied to each file found, before it gets added to the final output.

header

A comment that will be added to the top of the file from output. Useful for when you need to add specific instructions for contributors, especially for those who may not be aware that the file is auto-generated.

appendToConflicts

The string to be added to the end of filenames that have the same name as a directory in the same location within the javascript object.