The handlebars-helpers-ncc package contains 130 different utility dependencies including a few actually useful things like functions to convert Markdown to HTML, but also some weirdly trivial packages like is-even.
I suppose this was a brilliant way for the authors to generate staggeringly high NPM download counts for their packages: Repackage other people’s useful code into convenience functions and then include their own trivial package dependencies several layers deep to multiply their overall downloads count.
I wonder how many jobs they’ve applied to while bragging about their millions of monthly NPM downloads.
This is a very well known trick that we don't talk about much in public, but this is how most people with hundreds of repos on NPM get to this number.
One very popular terminal progress bar spinner has over 30 dependencies. One with the list of colors, another to display colors, another to clean the line, another to check if emojis are supported, another one with a list of emojis... plus a whole lot of wheel reinvention.
It was visible that most code in the sub-packages were just functions copied almost verbatim from StackOverflow.
It was also extremely limited when I tried to use it, and had quite a few bugs (it only really worked well on Macs at the time), despite the extremely large number of dependencies. Reimplementing took about 20 lines.
This is what drives me insane about NPM. Libraries are useful, and even package splitting utils like underscore or babel make sense in some scenarios. But it only takes a few packages like these to explode the size of the dependency tree.
Babel's splitting doesn't make much sense and is purely ideological. It's a monorepo, so split repos are not a development advantage. Plus, releases are often in sync. Plus, they recommend using presets rather than cherry-picking the specific plugins, making it kinda useless for end users. Plus, it's a CLI tool, so it's not really a necessary optimisation (and it would be a bad optimisation at that: having everything in a single package would make everything smaller and easier to compress).
For a long time, Babel plugins were entirely smoke-and-mirrors. If you looked under the hood at the source code of a "plugin" package, all it would contain was something like:
I found this out some years ago while investigating how I might write my own Babel plugin for some non-standard syntax. At the time there were no such facilities available, only the hidden built-in parser flags.
How long does it take to check the dependency tree of a package? If the package is trivial enough for it to not be worth to go through the dependency tree for 10-15 minutes, it wasn't worth it to include it in the first place. I'd rather have arbitrary depth of dependencies than some kind of governing system in NPM.
Wow, you just gave me a great idea for libc. Why not split it in libprintf, libscanf, libexit, libitoa, libstrbcpy etc. ? I'm sure the world will be better after this.
But from the average programmer's perspective this is clearly something they want. I see this general trend as a symptom of the inadequacy of JS to out-of-the-box address the tasks it's used for, which (as we note here) opens an outlet for spamming and security liabilities.
No. What programmers want are solutions to problems.
Nobody is asking for the madness of having proper-sized packages split into 100 smaller packages with zero advantages and actually a few disadvantages (difficult to audit, impossible to fork). This is what is being criticised here.
It would be perfectly fine to have a single `terminal-utils` package that contained all of this. And no, handlebar-helpers doesn't count.
> I see this general trend as a symptom of the inadequacy of JS to out-of-the-box address the tasks it's used for, which (as we note here) opens an outlet for spamming and security liabilities.
Two wrongs don't make a right. Package authors should not spam, regardless of the issues with of the ecosystem or language.
I get the ridiculousness of those tiny packages. On the other hand I also hate to have my codebase bloated by some kitchen-sink "util" package of which I'll use about 0.1% functionality. (while, if I were really strict, I'd also have to audit and track the remaining 99.9% of the code.)
Tree-shaking can help at least keeping the build artefact small, but it doesn't help with the codebase during development.
Of course there is still a difference between fine-grained dependencies and things that shouldn't be dependencies in the first place.
But the package that's generating all these numbers, handlebar-helpers, does precisely that. Sure, the spammer gets internet points, but those don't matter.
Security matters. Performance matters. Hackability/forkability matters. This kind of practice reduces security and auditability of systems, and makes projects harder to hack and fork.
From a security perspective what issues do you see besides auditability? It seems like the surface area for supply chain attacks is expanded needlessly by these types of shenanigans but I'm not sure how that translates to concrete impact to a project. I suppose resources required to scan and detect a package takeover are needlessly consumed but that's more upstream/centralized.
But I'm with you, this is ridiculous and auditability alone is reason enough to avoid it. Even if you were trying to make a case for composable packages this is absurd to the point that I wonder if it's self aware criticism of npm or an inside joke.
ansi-red is not a difficiency of JS. It's just stupid. It the equivalent of a package called add2 and another called add3. No language I know of has that built in and if it did it would arguably be a bad sign
It's ridiculous and amusing at the same time. However, I blame the people depending on libraries such this; not the opportunists enabling them. They either don't know what they are doing (incompetence) or can't be bothered to do anything about it (indifference). The combination of can't be bothered and wouldn't know how to is what leads to people using shit like this.
In the defense of javascript, dead code elimination is kind of hard because it is such a dynamic/messy language and that kind of pushes people in the direction of ridiculously fine-grained modularization. Languages with an actual type system and compiler tend to produce artifacts that only include code that is actually needed. That requires dead code elimination that actually works. Beyond what comes with the browser, there isn't much of a standard library. That's for the same reason. You'd either end up shipping the whole thing on every website or depending on some convoluted tooling in an attempt to strip it down to what you are actually using. Minification is of course a thing but it usually boils down to more obfuscating than actually removing dead code.
My strategy is to generally avoid the whole ecosystem as much as I can. I've been using Kotlin-js lately. Great libraries, runs in a browser, reactive styled components using fritz-2, web compose, or if you really insist react. You still get exposed to some of the madness (like webpack breaking between minor releases) but mostly you are shielded from that.
I don't think dead code elimination would be the end-all to that problem either.
Yes, it reduces the space cost of having dead code in your build artefact, but it doesn't solve the problem of having dead code lying around during development.
The more code is in your dependencies, the more effort you have in auditing - even if it's only to ensure that code is actually dead - and doesn't cause any unexpected side effects or other behaviour in your program.
Spammer is a polite definition. His background is in marketing, the business he links brandscale[.]com is broken/abandoned. How long until we see these packages used as trojan horses? Or sold to third parties?
umm... I just randomly checked and this person also seem to have packages which are of few lines. for e.g. I checked `is-fn`:
export default function isFunction(value) {
const type = Object.prototype.toString.call(value);
return type === '[object Function]' ||
type === '[object GeneratorFunction]' ||
type === '[object AsyncFunction]';
}
It can: JavaScript has a `typeof` operator that can be used for this. If you read the readme for is-fn, it points out that the package is only useful for code that needs to run in certain older browsers that have a buggy implementation of `typeof`.
I think that is sorted. If you go to the first result for `ansi-wrap` -> `ansi-gray` -> https://www.npmjs.com/package/fancy-log ("Log things, prefixed with a timestamp." by other creators: 2 398 259 weekly downloads)
It's very funny to me that these packages exist while one of his bigger projects (https://github.com/enquirer/enquirer) lists the following reason under "why use it":
> Lightweight - Only one dependency, the excellent ansi-colors by Brian Woodward.
> Several years ago I switched careers from sales, marketing and consulting[1]
The author's bio on his GitHub profile explains it: he's approaching development with a mindset of sales and marketing. It's also followed by his GitHub stats front and center.
> I wonder how many jobs they’ve applied to while bragging about their millions of monthly NPM downloads.
isEven claims to be a learning project. It depends on isOdd and isNumber, both of which were admitted (IIRC) to be explicit NPM download boosting projects. Such that the author of isOdd added it to major modules whenever they could
Looks like the author of these packages agrees. While the is-even and is-odd packages are under the i-voted-for-trump user with the description "This is a joke", the is-number package [1] is still kept under the main profile of the author, the repository is still active on GitHub and there are active issues.
In the type of things that Javascript considers 'numbers', it's a value used to indicate that it's not of the type of things that math considers 'numbers'.
Comparing it against the list of examples given in is-number, this solution does not properly handle numbers represented as strings, and it also recognizes Infinity as a number.
Strings are the safest way to hold big numbers in JavaScript due to how JavaScript represents numbers. Also no, infinity is not a number. It's a concept.
Numbers is a concept. For some purposes it is useful to consider a number that is infinite, which is why concepts like the extended real number line have been invented.
> I wonder how many jobs they’ve applied to while bragging about their millions of monthly NPM downloads.
I used to work for a company where it was ok (managers won't say anything, even if explicitly pointed at the situation) to remove company company code, create your own NPM package (on your own private NPM account) and add it as a dependency of the company codebase(s).
This and some other similar behaviours were the reason I left that company. But I'm the loser of the story here, as those guys are now working for even bigger companies with bigger salaries than me.
> But I'm the loser of the story here, as those guys are now working for even bigger companies with bigger salaries
Another way to look at this is that a lower-paid SWE is paying for their mental health and morale. In my books, that's a winner :)
With the assumption that those engineers whose high/er salary in big/ger companies is not achived through mastery (Netflix is certainly not going to hire the Jon Schlinkerts), they're likely going to work with, say, "moral peers", which is typically undesirable for mentally healthy people.
Well... if the actual Open Source work you do is in your day job except that instead of committing to the internal codebase you commit in your own packages all day and then update the dependency in the project, I don't think you need to be 10x.
You must be kidding me. Color me old-fashioned, but software development for me is still a "serious" job - one that requires years of training, focus and patience to get through all the matter.
And you tell me these people don't give a single fuck?
The author is a staunch anti-vaxer in addition to an open source huckster which seems to line up the fallacies of his “contributing to open source” with his willingness to spread lies about COVID and the vaccine.
Patreon and Github Sponsorships are popular ones. But also being able to add to their Resumé, being popular and leveraging it for other activities like talks and interviews, etc.
I think the horseshoe is almost coming back around to the point where people criticizing NFTs are bringing them up more often and in more annoyingly-out-of-context ways than the crypto people themselves...
I mean the first guy who did it on the creativity, maybe the first 10, but nowadays that just means you can't think of anything else to boost your profile.
That's great hire them, then it will have served it's purpose. They can repackage all their trivial number related stuff up into one generally useful module, deprecate the old trivial ones and everybody can get back to work (with a smaller number of dependencies).
Ha, I remember this package. It's a dependency of a dependency of a dependency in several projects inside the company I work for. I think either React, Babel, or Webpack depended on it at some point in time.
Nobody needs to write satire about the state of Javascript package management when people write (and use!) libraries like these.
The “Usage” section in the readme doesn’t even give you any information about how it behaves on inputs that aren’t numbers. I hope the is-odd package has some way of detecting whether the input is a number or not. Maybe other packages need this too!
Seems to me that the name is satire. As in, the author didn't actually vote for trump but wants to make it look like people that voted for him are creating packages like that.
I don't think such packages should be on NPM either way.
His twitter feed is full of right wing talking points and he broke a 19 year voting hiatus to vote in the 2020 general election, so I don't think it's that unreasonable to think he did, in fact, vote for Trump.
I wish some of these large projects would start seriously auditing their dependencies and stop pulling in dependencies that have many dependencies themselves. There is a one-two punch of a culture of "there's a package for that" and npm not requiring flat dependency trees by default. The denial in the node community that npm is uniquely bad is frustrating. I want the community to stop denying and own these issues so things can get better. It's going to take the authors of large packages to start evangelizing the use of fewer, higher quality packages, using flat dependency trees, and re-implementing trivial functions instead of adding another node to trust.
There is a bit of a culture clash inside Javascript. Even when you're a veteran contributor, sometimes maintainers resist changing packages, as simple as they are, because there is an implicit assumption that popular packages, or even packages with too many dependencies are "better" or "handled all the edge cases".
Even with careful evaluation of the options and a write-down of issues and a proper comparison, you need ten times as much energy to remove a package than it took to add it.
It's even worse is when "too many packages" is in the DNA of the package you're collaborating.
Don't forget too that npm by default allows minor version upgrades with the ^ prefix for version numbers, which means that unless you properly lock your dependencies, you can reintroduce changes over time, just by running npm install.
const isNumber = require('is-number');
module.exports = function isOdd(value) {
const n = Math.abs(value);
if (!isNumber(n)) {
throw new TypeError('expected a number');
}
if (!Number.isInteger(n)) {
throw new Error('expected an integer');
}
if (!Number.isSafeInteger(n)) {
throw new Error('value exceeds maximum safe integer');
}
return (n % 2) === 1;
};
That horrible realisation that because of its dependency on is-number, and all of its checks and pretty error messages I can imagine there's actually some valid use cases for this package. You can plug this right into a user input validation system and it would work perfect for production use cases in a way that num % 2 === 0 just wouldn't.
Almost other use case for it though.. horrible. This package would be much better if it was in some sort of namespace that indicated it's for user input validation only.
Also a check for Infinity (Infinity - Infinity -> NaN)
Which is weird since they use the isFinite built-in right after that, but I have no idea why they throw in all the string checks and trims and + for type coercion, and then use the global isFinite function which does all that internally. In fact the global function isFinite does everything this package does
(something I just learned tho checking this code out is that there is a global isNaN and isFinite which coerce strings into numbers automatically, and Number.isNaN and Number.isFinite which function similarly but without coercing the string first, so I guess this package exists as a learning aide of all the different ways to ask if something is a number)
EDIT: I now know why they check if a string input is not an empty string, because empty strings get coerced to 0, so isFinite("") returns true.
Number.isFinite('') and Number.isNaN('') returns false, isFinite('') and isNaN('') returns true, the global versions of isFinite and isNaN first coerce their input to number, no '+' necessary.
The MDN compatibility data says IsNaN was in node as of 0.10.0, which was released 2013-03-11. NPM says the library was first published 2014-09-21. And the library uses isFinite which was added in the same Node version. So... not really, no.
Anyway, my point wasn't so much that the code is an outrage, more that should anyone stumble across this comment thread they know that there is a much clearer and more obvious way to check for IsNaN than using x-x===0.
Sorry, I misunderstood which isNaN you were talking about. The global isNaN has unexpected behavior in certain edge cases[1], so that's probably why the library author chose to avoid it. Number.isNaN doesn't have that behavior, but is not supported in IE.
I agree most people these days should just use Number.isNaN, assuming they don't need to support IE.
this library uses the global isFinite, which actually you could just use instead of the whole function, since it does the string coercion and infinity check for you.
Check out the compatibility table on MDN, Chrome Firefox and Safari version 1 all support it, so I'm pretty sure isNaN and isFinite were in the original spec.
See the MDN section on "confusing special case behavior"[1] for why they probably didn't want to use the global version of isNaN. Number.isNaN handles those cases better but is not as widely supported.
So in conclusion... maybe checking whether a number is even in JS isn't as trivial as everyone thought, and projects reusing that code was a good thing?
Or are are all those extra checks unnecessary now that TypeScript exists and new functions like Number.isInteger have widespread browser support?
I think the assertion (sorry for the pun) is that JavaScript is a completely unholy creation and should be chucked off the edge of the disc.
I can’t imagine trying to get some of our fintech business logic in there without arming a nuclear foot gun or ten. I would never sleep again without medication.
2̶7̶ 2 dependencies, travis ci configured, fully tested and documented, even the readme depends on some external tool. github username is i-voted-for-trump. Looks like a joke that people actually started using.
27 dependents, i.e. things depending on it. Only one dependency: is-odd, hilariously.
I'd like to think it's a joke, but maybe not. Anyway, what's with the massive download spike, 20 million downloads between 22nd and 28th December 2020.
It would be one thing if it was _just_ a little demo utility used to showcase packaging and distribution of a trivial use case, however the creator of this has also created a number of packages which pull in these "demo" packages, like `handlebar-helpers`, which is again just these trivial function packages wrapped in handlebar decorators.
Several of these utility and helper packages are then pulled into other packages and build tools and marketed as legitimate packages, effectively hiding and masking the "just a demo" labels of the root is-even, is-odd, is-number packages. When people like myself complain about the absurdity of NPM supply chain verification, this is what we're arguing against.
Adding a package like this as a dependency is a net negative, because for the sake of trivial functionality you take on all the supply chain overhead and security risk.
The culture of relying on small dependencies needs to adapt to account for security. It's one of many aspects of open source supply chain management due for a reckoning.
But, honestly, do developers these days just not have their OWN libraries of code they bring along with them? Are they SO dependent on others they can't write trivial code?
I reckon that centralized package management actually _reduced_ the amount of people relying on their own library of snippets. Why bother saving how you solved Problem A, when there is probably a package doing it better...?
Ironic that this post makes it to front page but an admission that any npm package published before 2020 may have been hacked gets no interest! https://news.ycombinator.com/item?id=29234098
>Ironic that this post makes it to front page but an admission that any npm package published before 2020 may have been hacked gets no interest! https://news.ycombinator.com/item?id=29234098
Not ironic. That article's unfortunate and misleading title isn't nearly as eye-catching as one describing the true nature of its content; a deliberate decision.
> This is a joke. You'll only see this org if you are attempting to troll me about repositories I created when I was learning to program.
I give this troll effort a score of 9/10. Well done - love the testing, readme, docs, continuous integration, etc. Honestly, this is better than most enterprise software I see.
I might contribute for fun and lulz...
EDIT - read some of the comments and there is some anger and confusion. Folks, this is a troll. Yes, npm and the JS ecosystem have some flaws, but let's not get bent out of shape.
> From the github user's ("i-voted-for-trump") bio:
> EDIT - read some of the comments and there is some anger and confusion. Folks, this is a troll. Yes, npm and the JS ecosystem have some flaws, but let's not get bent out of shape.
It doesn't look like so. The author is definitely creating some confusion with redirects, but the readme of his professional Github's account (https://github.com/jonschlinkert) says:
> Several years ago I switched careers from sales, marketing and consulting to learn how to program, with the goal of making the world a better place through code. [...] To date, I've created more than 1,000 open source projects in an effort to reach my goal. Open source software takes a lot of time to create and maintain. You can help me to achieve my goals of changing the world through code, help me create better developer experiences, or just say thank you by sponsoring me on GitHub.
He's asking for real money; he's definitely not a troll.
Why can't NPM has something like Apache commons? There you can include all simple and fundamental functionality. Instead of having one package each like this.
Why couldn't Javascript have ever built a halfway decent standard library?
Much of the terribleness of the current programming environment could have been rectified if this fundamental failure had not been allowed to continue.
I reckon the problem is simply that the bar for entry in that world is non-existent. Anybody can learn html and javascript in a couple of days, so there is no filter. It's a blessing and a curse.
But yes, a JS stdlib would solve 95% of the joke-level problems with the ecosystem.
In fairness, I should mention that I haven't written much javascript myself over the years, so using CRA to quickly get a simple SPA off the ground has been rather nice of late.
It's opinionated and has worts, but ~3 commands and you're 'off the the races' is hard to argue against.
Javascript has a perfectly decent standard library for its intended use case - scripting webpages. It was never meant to be a general purpose application or systems programming language. It was never meant to be used outside of the browser, much less to replace C++ and other languages in their respective domains.
The "current programming environment" is the problem, and it doesn't exist because Javascript is superior to other languages, and should be used everywhere, but only because web developers are easier to find and cheaper to hire.
And in any case, you could ship a "standard library" for javascript that covers most common use cases in a single static file. We used to do that, it was called JQuery. Even assuming for the sake of argument that Javascript's standard library is lacking, that doesn't justify the mess that is Node's micropackages.
Yes, but it's not a "halfway decent" standard library because it does not include so many basic things that would be expected to be in the standard library.
I'm not sure what to think about this guy, but I think it's more guilty those packages that decide to depend on these dependencies rabbit holes and is also fault of the platform for not showing how deep the dependency-chain goes.
We should focus more on improving how we choose dependencies
How does your company protect itself against supply chain attacks on NPM? At my company, we try to keep dependencies at a minimum, but I doubt this is effective as a protective measure.
State exact versions and checksums of all deps plus run your own server hosting the deps and firewall it from accessing the internet at large. Only update deps when needed. This is what we have to do in our env.
isEven is ridiculous but appears to be a joke so thats fine. isOdd being an actual dep is ridiculous and i dont think its a joke? edit: yeah is-odd seems to be a serious project. This is one of the first things people learn in a new language and we have a package for it? I guess its a teaching point? or maybe the author just wanted reputation..
just bizarre considering javascript has isNaN, Number.isFinite, and Number.isInteger; I guess there's a style of development where you check if what you want to do exists in npm first, without thinking about what the language itself offers.
> it's not too bizarre when you consider no version of IE supports Number.isFinite or Number.isInteger.
If you are extensively using nodejs libraries to target IE, then you have other problems than supporting Number.isFinite or Number.isInteger to deal with first, considering that IE doesn't support modern ES versions in anyway. You'd have to use shims,polyfills and whatnot at first place and transpile all that npm code into something IE can run.
This isn't a very good argument to add an "is-even" package.
but this is an npm package, would a client side application be importing this code? surely at that point you could just include some Number polyfill as well (but you're right I was only thinking of node)
No, by taking care of all the exception handling these packages do. It's why these stupid packages exist: because the standard library doesn't handle them.
This approach is called “garbage in - garbage out”. The idea is, you can add extra checks and sacrifice some performance. But if checks are built in there is no way to remove them, even if you don’t need them and they hurt performance. Clojure’s standard library uses “garbage in - garbage out” approach too.
> But if checks are built in there is no way to remove them
Sure there is: you have a compiler which recognizes uses library functions and makes code generation decisions based on whatever information is available at the call site.
And this is easier to do for built-in functions, whose definition you can assume from the spec.
The simplest example is constant folding. If isEven is part of the language, a compiler can constant-fold isEven(0) to true even if no inline definition of it is visible.
That kind of "exception handling" is what I use Typescript for. JS decided back around ES4 that type hints were too complicated for browsers and they've been left to outside tools like Typescript and Flow.
I'm not always sure that was the right decision long term, but that was an informed decision of the time.
If you have that kind of problem then maybe you should sanitize whatever the input is first, then check with parseFloat and isNaN if the value IS a number.
If you are sending arrays to your modulo check then obliviously your code has a logical error.
These packages serve a very useful purpose in that they illustrate dependency abuse, but the fact isOdd DEPENDS ON isEven and isNumber is pretty funny.
Funniest thing about this is that is-even requires as a dependency another node package written by the same author, called "is-odd." the is-even code just returns !is-odd. The "is-odd" package actually contains the logic for determining if a number is odd or even.
This issue of dependencies is exacerbated when a popular library has old and unmaintained dependencies 2-3 levels down that have security holes, and taking them out is a huge refactor.
I hope the JS community is moving away from this model, and I think a good example of that is DayJS.
So, who's going to be the person to find all these dumb packages and replace them with PR's to their dependents? Make PR's to repos using is-even, is-odd, etc with n % 2 == 0; etc?
I went looking through the dependency chain of this for even more popular simple packages and picked a 4 million/month package that was calling is-number thinking it must be added to most of these as a joke/snuck it in and it turned out it was the original/main dev that added the dependency. So it seems the best case scenario of "fixing it by PR" is every PR request is accepted even though it was (at least sometimes) intentionally added by the main dev and this is done continuously and endlessly for this and every package like it (there seem to be hundreds of equally trivial packages that are popular) yet they problem will still continue to exist anyways.
Not that there is anything wrong with greatly reducing the usage rate when we can just the real interesting problem presented with this package isn't literally the package itself it's troubles in the dependency ecosystem of NPM.
All that said I'm going to try to tackle a handful after work, particularly of is-number which is about as many lines to import as define and unchanged for many years.
Turns out the vast majority of the uses are semi reasonable basic utility packages by the same authors as the clearly trivial packages. They include their own work many times and a few larger projects legitimately use the reasonable basic utility packages. This results in millions of downloads of these frivolous packages with no interest from the maintainer in removing their own fluff dependencies.
The only way to get past (the vast majority of) these would be to rewrite the mid level utilities and get projects to sign off on that larger switch (either as a dependency change or as a duplication of that code directly). Unfortunately that's not a "if a bunch of us clear 5 out tonight NPM's dependency hell will be fixed" kind of solution.
Replacing it with just that would be a bad idea, since (see upthread, where the code's posted) it also verifies that its argument is an integer, erroring if it's not. Some code out there might be relying on that functionality, and hell, type coercion might even do something crazy without those checks, turning erroring-bugs into data-corrupting bugs.
During the week between 22nd and 28th Dec 2020, it shows a spike. Not an ordinary one, but more than 100x the regular figure! 19,960,098 downloads to be precise.
this may no seem like an odd comment (please at least admire the pun), but generally I can see value in this. All this stuff is-even and is-number is doing to make sure that it is actually a number, throwing errors etc. pp. sure, I could do it myself, but I would probably miss half of the cases and would spend some time finding the right solutions for the other half. Why I should reinvent the wheel if someone already has, and that in a good and thought through way?
Don't get me wrong, there are tons of needless packages on npm, but in this case I can see the value (ok, maybe the is-odd is one too much and !is-even would be enough)
just to to trigger a bit more: Pretty sure a case manufacturer could develop it's own screws... but I think in most cases they just use what someone else provides...
It's well respected, battle tested, and you can just pull in the functions you actually use. It doesn't have isEven, but it probably drew a good line there.
722K of those downloads come from this package by the same authors: https://www.npmjs.com/package/handlebars-helpers-ncc
The handlebars-helpers-ncc package contains 130 different utility dependencies including a few actually useful things like functions to convert Markdown to HTML, but also some weirdly trivial packages like is-even.
I suppose this was a brilliant way for the authors to generate staggeringly high NPM download counts for their packages: Repackage other people’s useful code into convenience functions and then include their own trivial package dependencies several layers deep to multiply their overall downloads count.
I wonder how many jobs they’ve applied to while bragging about their millions of monthly NPM downloads.