NPM – "is-even", 160k weekly downloads
npmjs.com
npmjs.com
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.
You mean how broken it is, and how to take advantage of it? Depending on your business they could fit in really well.
I wouldn't want to work with this person.
And stretching the idea, people who download is-even for serious purposes are probably amongst the hopeless naive/inexperienced ones
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
e.g: [1, "one", true, false, 0, "zero", null, undefined]
edit: also ["1", "0", etc]
edit 2: also [NaN]
“number" == typeof variable
Works for decimals, too.Although maybe you meant to include
"1"
In your examples? "number" === typeof NaN
Returns true.Now, the fact that IEEE754 is insane is something else, but JS does nothing wrong (aside from not having not-floats)
JS has BigInt - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
const allowNumbers = {
all: () => true,
notNaN: n => !Number.isNaN(n),
finite: Number.isFinite,
integer: Number.isInteger,
smol: n => Math.abs(n) < Number.EPSILON,
lorge: n => n > Number.MAX_SAFE_INTEGER || n < Number.MIN_SAFE_INTEGER,
}
function isNumber(n, allow = allowNumbers.all) {
return ("number" === typeof n) && allow(n);
}Any weird edge cases against this one?
typeof v === "number"
The rest is parsing territory.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.
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.
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.
and create another future opportunity for a supply chain attack
require('babel').____secret____.enablePluginFoo = true;
There was no actual plugin API, just selectively-enabled logic hardcoded into the main packages. The whole thing was fake-it-til-you-make-it.Actual plugins for non-standard syntax were all real AST visitor-based modifications, though.
Do people really do this? Does this explain the dumpster fire ecosystem of NPM?
...but interviewers often assume that they are all useful packages and that the numbers are not inflated.
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.
s/projects/functions
Related projects
----------------
ansi-reset
ansi-bold
ansi-dim
ansi-italic
ansi-underline
ansi-inverse
ansi-hidden
ansi-strikethrough
ansi-black
ansi-red
ansi-green
ansi-yellow
ansi-blue
ansi-magenta
ansi-cyan
ansi-white
ansi-gray
ansi-grey
ansi-bgblack
ansi-bgred
ansi-bggreen
ansi-bgyellow
ansi-bgblue
ansi-bgmagenta
ansi-bgcyan
ansi-bgwhite
That fucking ansi-red "package" has 1.3M weekly downloads.I have to actually check to make sure he doesn't have packages like regexp-left-parenthesis, regexp-dot, etc.
Is there a site or code snippet where I can see which of the popular dependants was fooled into using this crap and is driving most of the downloads?
var wrap = require('ansi-wrap');
module.exports = function red(message) {
return wrap(31, 39, message);
};
And ansi-wrap: module.exports = function(a, b, msg) {
return '\u001b['+ a + 'm' + msg + '\u001b[' + b + 'm';
};
Now imagine those things inside a real utility that gets adopted by some popular package.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.
Precisely what? That's not one self-contained package I said is okay.
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.
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.
Especially when most of those packages are almost never used by themselves, and are instead part of a meta-package with dozens of dependencies.
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.
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.
export default function isFunction(value) {
const type = Object.prototype.toString.call(value);
return type === '[object Function]' ||
type === '[object GeneratorFunction]' ||
type === '[object AsyncFunction]';
}
This has 120k weekly downloads: https://www.npmjs.com/package/is-fn> Lightweight - Only one dependency, the excellent ansi-colors by Brian Woodward.
And you tell me these people don't give a single fuck?
Look at the guys Twitter: https://mobile.twitter.com/jonschlinkert
The sad thing about this is that people will buy it too
Nobody needs to write satire about the state of Javascript package management when people write (and use!) libraries like these.
https://github.com/i-voted-for-trump/is-even/blob/master/pac...
2.7.3 :003 > 1.odd?
=> true
2.7.3 :004 > 2.odd?
=> false
2.7.3 :005 > 1.even?
=> false
2.7.3 :006 > 2.even?
=> true
2.7.3 :007 >EDIT: Confirmed, it was added in 1.8.7 according to Ruby Docs [1] [2]
[1] https://ruby-doc.org/core-1.8.7/Integer.html (present)
[2] https://ruby-doc.org/core-1.8.6/Integer.html (not present)
isEven(0);
//=> true
isEven('1');
//=> false
isEven(2);
//=> true
isEven('3');
//=> falseI don't think such packages should be on NPM either way.
This is what it says there:
> 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.
https://mobile.twitter.com/jonschlinkert
He definitely voted for trump.
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.
'use strict';
var isOdd = require('is-odd');
module.exports = function isEven(i) {
return !isOdd(i);
}; 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;
}; 'use strict';
module.exports = function(num) {
if (typeof num === 'number') {
return num - num === 0;
}
if (typeof num === 'string' && num.trim() !== '') {
return Number.isFinite ? Number.isFinite(+num) :
isFinite(+num);
}
return false;
};https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
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.
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
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.
I agree most people these days should just use Number.isNaN, assuming they don't need to support IE.
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
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.
Yes, when coerced with +:
Number.isFinite(+'') // true
Number.isFinite('') // falseHence the heading "Confusing Special Case Behavior" in the mdn docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Or are are all those extra checks unnecessary now that TypeScript exists and new functions like Number.isInteger have widespread browser support?
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.
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.
var isOdd = require("is-odd");
console.log(isOdd([1])); // TRUE!! 'use strict';
var isEven = require('is-even');
module.exports = function isOdd(i) {
return !isEven(i);
}; function isOdd(i) {
return i > 0 && isEven(i - 1);
}
function isEven(i) {
return i == 0 || isOdd(i - 1);
}https://www.npmjs.com/package/is-even-cyclic has a cyclic dependency with https://www.npmjs.com/package/is-odd-cyclic.
edit: Confused dependents with dependencies
> I created this in 2014, when I was learning how to program.
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.
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.
> 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
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?
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.
Does saying dang 3 times work?
From the github user's ("i-voted-for-trump") bio:
> 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.
> 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.
Well, his Twitter is on point.
Anyway, I'm pretty sure it wasn't a joke originally. I recall him heavily defending it even after people trolled him for creating such a package.
Much of the terribleness of the current programming environment could have been rectified if this fundamental failure had not been allowed to continue.
https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how...
Stupid debates over a formatting tool - or in this case, a simple conditional - should tell you that something is seriously FUBAR in Javascriptland.
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.
Because it's consensus-driven, and that consensus is achieved on meetings organized every ~3 months.
And because of strict backwards compatibility rule, everyone is extremely cautious.
I tried to add new methods to Set, but proposal is basically being held hostage by subclassing proposal. https://github.com/tc39/proposal-set-methods
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.
> i-voted-for-trump
> 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.
> is-odd
> I created this in 2014, the year I learned how to program. All of the downloads are from an old version of https://github.com/micromatch/micromatch. I've done a few other things since: https://xn--gith-tc7a
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
I think what that Schlinkert guy is doing is obviously grifting, so I don't have to speculate on his intentions to call him a grifter.
>>is-even/package.json
"dependencies": {
"is-odd": "^0.1.2"
},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.
var isEven = require('is-even');
module.exports = function isOdd(i) {
return !isEven(i);
};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.
I'm not always sure that was the right decision long term, but that was an informed decision of the time.
[] % 2 === 0 //true
[234] % 2 === 0 //true
"" % 2 === 0 //true
new Date() % 2 === 0 //sometimes true
"but think of all of the time and keystrokes I saved by not having to call .toString()!", they'll say...
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.
'use strict';
var isOdd = require('is-odd');
module.exports = function isEven(i) {
return !isOdd(i);
};
https://github.com/i-voted-for-trump/is-even/blob/master/ind...Hmmm... Why NPM? Why Node.js?
I am staying well clear of this in any important infrastructure.
I build test frame works out of Node.js (I had a set of bad choices) so I can get to know the thing. Made me hate it more.
All the mistakes ever made in computing rolled into one convenient system. Do not use this in important infrastructure. It is very bad.
Interesting, 845 repositories by the user, and the vast majority of them are simple NPM modules such as this one.
Has there been any recent instances of someone abusing simple NPM repos like this for malicious intent?
I hope the JS community is moving away from this model, and I think a good example of that is DayJS.
https://www.npmjs.com/package/is-odd-or-even
that of course depends on is-odd and is-even.
I will pay you cash to delete your NPM module https://news.ycombinator.com/item?id=29240952
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.
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.
Edit: whoops, 100x
it has almost 90k downloads a week
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.