Library / SDK
documentcloud/underscore-contrib avatar
documentcloud/underscore-contrib

underscore-contrib: a contributors' library of helpers

The brass buckles on Underscore's utility belt

622 stars114 forksJavaScriptMIT

At a glance

What is it?
This is a holding pen of standalone modules that extend the core library, split across arrays, collections, functions, objects and utilities. Its stated purpose is twofold: a home for narrowly scoped helpers that solve a point problem, and a proving ground for features that might belong in the core library itself if they can be argued into existence.
Who is it for?
The library fits a JavaScript codebase that already depends on the core library and needs one of its narrower helpers, such as trampolines, arity control or function combinators, without pulling in a large library to do it. It does not fit a modern codebase that has moved on from a script tag setup, and it is not a foundation for anything new, since the collection is deliberately a holding pen.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A holding pen with two stated jobs

The README describes the project as the brass buckles on the core library's utility belt, and it gives a precise reason for existing separately from the library it extends. The core library provides a bevy of useful tools for functional programming in JavaScript, but it cannot and should not be everything to everyone. This contrib library is intended as a home for functions that, for various reasons, do not belong in the core library proper.

Two roles follow from that, and the README names both. The first is a home for functions that are limited in scope but solve certain point problems, which is the pragmatic role. The second is a proving ground for features that belong in the core library but need some advocacy and evolution, or devolution, to get them there. The parenthetical is doing real work: a feature can arrive here in one shape, get argued about, and leave in a different shape, possibly not at all.

That framing explains the shape of the repository better than a feature list would. A collection like this has no coherent theme beyond being adjacent to the core library, and the file names reflect that. The top level holds one file per topic, with a consistent naming scheme that pairs a namespace with a subject: a builders file and a selectors file for arrays, the same pair for objects, a walk over collections, and function-side files for arity, combinators, dispatch, iterators and predicates, followed by utility files for existential checks, operators, strings and trampolines. There is an index.js at the root and a bower.json for the package manager of the era.

Reading the names tells you what the collection actually contains: not a coherent library, but fourteen small, single-purpose additions that happen to share a dependency.

Every module stands alone, and that is a promise the README qualifies

The usage instructions are browser-oriented and short. You need the core library first, then you grab the relevant contrib file and add a script tag for it to your pages, pointing at the core library and then at the specific contrib file you want.

The important detail is the parenthetical in the README: at the moment there are no cross-contrib dependencies, in other words each library can stand by itself, but that may change in the future. That is a small sentence carrying a real constraint. Today you can include one file and get a working module with no ordering requirements between contrib files. The moment two of them start depending on each other, you are back to managing load order, and the README says so plainly rather than promising it will never happen.

The dependency on the core library is pinned exactly. The package.json lists a single runtime dependency, the core library at version 1.10.2, with main pointing at index.js, and the package version is 0.3.0.

For the tree shaking and bundle tool era, this shape is a liability rather than a feature. A file-per-function library with a global script tag is not something a modern bundler can tree shake, because there is no import graph inside the library. You would be copying a file into your source tree, or pulling a single file from the package by path, and either way you take on the maintenance of that file rather than upgrading it with the rest of your dependencies. The examples directory has a single file, walk-examples.js.md, which shows the documentation style the project expects for that kind of artifact.

Grunt, JSHint and QUnit do the building, testing and docs

The tooling is visible in the repository root and in package.json, and it describes the workflow contributors are expected to follow.

The package.json scripts are a thin wrapper over Grunt: test runs grunt test, dist runs grunt dist, and there are separate tasks for tocdoc and docco. The devDependencies list is the Grunt plugin set: grunt-contrib-concat for concatenation, grunt-contrib-jshint for linting, grunt-contrib-qunit for running QUnit tests in a browser context, grunt-contrib-uglify for minification, and grunt-contrib-watch for rebuilding on change, plus grunt-docco and grunt-tocdoc for the annotated documentation. QUnit itself is a devDependency, along with jQuery 3.5.1 and jslitmus, which was the microbenchmarking tool of that period.

The result is a documentation pipeline rather than a plain one. grunt-docco and grunt-tocdoc generate annotated source documentation, and tocdoc.css at the root is the stylesheet for the generated table of contents, so the published docs are produced from the source comments by the build rather than maintained as separate files.

There is a DEPLOYING.md at the top level and a CHANGELOG.md, which together with the dist task describe how a release is assembled and published. The deployment steps live in a separate document from the README, so anyone maintaining the repository has a written procedure for producing the distributable files rather than improvising one.

Contribution comes with a documentation and evidence requirement

The contributing section is unusually specific about what a proposal needs.

It starts by acknowledging that there is still a lot of work to do around performance, documentation, examples, testing and distribution, and that help in those areas is welcome. Then it sets the process for new code: pull requests are accepted, but you should search the issues before proposing a new sub-contrib or addition. That instruction is the repository's answer to the sprawl risk of a collection like this, since the issue tracker is where the argument about whether a function belongs in the core library would happen.

The bar for a patch is stated next: all patches and proposals should have strong documentation, motivating cases and tests. Motivating cases means a worked example of the problem the function solves, and tests means it arrives with the QUnit suite.

The stated ambition is broader than the function library. The README says it would be nice to provide not only useful tools built on the core library but also an educational experience for why and how one might use them. That is why documentation weight sits alongside code in the requirements, and it is the part of the project most likely to be judged valuable by a reader today even if they never import a single function from it.

The maintainer is identified in package.json as Fogus, with the maintainer website linked from the README, and the repository sits under the documentcloud organisation, the same one behind the core library itself.

The list of things it might add next is an open discussion

The README ends with a list of other, potentially useful sub-contribs, and it is worth quoting the categories rather than the framing: string utilities, date and time utilities, validators, iterators, generators, promises, monads, currying, laziness and multimethods.

Two of those already exist in the tree in some form. Iterators and combinators are there as function-side modules, and laziness in the functional sense is covered by the trampolines file. That the list still mentions them suggests the list is a wish list rather than a status board.

The closing line is the tell: what do these mean? Well, that is up for discussion, with a smiley. This is a project that treats its own backlog as an open question rather than a commitment, which is consistent with the proving ground role stated at the top. A sub-contrib in this repository is a proposal that someone argued for, and the argument is part of the deliverable.

The practical reading for an adopter is that nothing on this list is a feature to plan around. If you need promises or multimethods in this style, decide whether they belong in your own codebase, because the repository is telling you it has not settled the question of whether they belong here at all.

There is also a distribution question left open. The README's list of areas needing work includes distribution, and the repository still ships the era's bower.json alongside package.json, which tells you how wide the gap is between this project and current packaging practice.

A library with no release tags and a pinned dependency

The maintenance picture is thin, and it should be read carefully.

The repository is not archived and the last push was on 2026-10-18, so work is still landing. The package version in package.json is 0.3.0, and the repository publishes no GitHub releases, so the version in the manifest and the commit history are what you have to work from. CHANGELOG.md exists in the tree without a version schedule attached to it.

The dependency pin is the sharpest edge. The core library is pinned to exactly 1.10.2 with no range, so installing this package gives you that precise version rather than whatever your application also wants, and any conflict has to be resolved by hand in the dependency tree.

The licence is MIT, which is the easy part of the assessment: no copyleft obligations, no attribution requirements beyond keeping the notice, and no restrictions on commercial use.

So the honest summary is that this is a small, well documented, lightly maintained collection of helpers that has not been modernised in its packaging. If you need one function from it, the file is readable, tested and MIT licensed, and you can copy it with confidence. If you are choosing a general purpose utility library for a new project, this is not that, and the README says so in its first paragraph.

Editorial conclusion

The library fits a JavaScript codebase that already depends on the core library and needs one of its narrower helpers, such as trampolines, arity control or function combinators, without pulling in a large library to do it. It does not fit a modern codebase that has moved on from a script tag setup, and it is not a foundation for anything new, since the collection is deliberately a holding pen. Before importing a module, check the exact core library version it was written against, because package.json pins 1.10.2, and read the module's own documentation and tests, because the README asks that every patch carry strong documentation, motivating cases and tests.

Frequently asked questions

What is underscore-contrib for?

It is a contributors' library for the core library, intended as a home for functions that are limited in scope but solve point problems, and as a proving ground for features that belong in the core library but need advocacy and evolution before they get there.

How do I use the contrib modules in a page?

You load the core library first and then the specific contrib file you need, with one script tag per library. The README notes that at the moment there are no cross-contrib dependencies, so each library can stand by itself, though that may change in the future.

How are the contrib modules tested and documented?

The build is driven by Grunt with grunt-contrib-qunit for tests, grunt-contrib-jshint for linting, grunt-contrib-concat and grunt-contrib-uglify for building, and grunt-docco with grunt-tocdoc for annotated documentation. package.json exposes npm scripts for test, dist, docco and tocdoc.

What does a contribution to the contrib library require?

The README asks you to search the issues before proposing a new sub-contrib or addition, and says all patches and proposals should have strong documentation, motivating cases and tests. It also notes there is still work to be done around performance, documentation, examples, testing and distribution.

Official sources

  1. documentcloud/underscore-contrib on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/documentcloud-underscore-contrib.svg)](https://hysenlabs.com/projects/documentcloud-underscore-contrib)

Was this useful?