v0.1.0

Delete the dependency. Keep the code working.

nirdep reads your imports, rewrites the ones it can prove are safe, refuses the rest out loud, and hands you the replacements as plain files you own. Nothing is installed. nirdep itself leaves nothing behind -- not even nirdep.

0 dependencies Node 22.17+ MIT source

Fourteen commands, on one broken project

A project called acme-release-notes that imports chalk, semver, lodash and minimist. Every command below was really run against it while this page was being built -- by spawning the actual bin/nirdep.mjs, in order, on one copy of the project, so scan after apply is quiet because the apply above it really happened. What you click is the replay: the bytes it printed, exit code and colours included. Nothing executes in your browser here, and the page would rather say so than pretend.

Or type one. help, clear and the names above work; anything else is answered honestly.

acme-release-notes — nirdep v0.1.0 replay, not execution
$

Four ways a dependency turns on you

Every row in these stories comes out of src/scan/advisories.mjs, the same table nirdep scan checks your lockfile against. The build fails unless all 0 rows are claimed by exactly one story, so these cannot quietly go stale while the table moves on. Open one and the advisories are listed underneath the argument.

Reviewed . This is a hand-kept table with a date on it, not a feed. It is not npm audit and does not pretend to be complete.

Measured, including where we lose

Written by node tools/bench.mjs and committed as bench.json. The page reads that file; it never runs the benchmark, because a number that changes every time the page is built is a number nobody can check. Three of these are honestly slower than the package they replace.

nirdep the package it replaces Each pair is scaled to itself, so the two bars in one column can be compared and two different columns cannot: operations per second only means something against the same work. A missing grey bar means that package was not on the machine that ran this, and the figure is left out rather than filled in.

What the five files cost you to keep

The whole tool, on 300 files

The gap between those last two rows is the syntax gate: every rewritten file goes to Node's own parser before it is written, which costs a process per file. It is the most expensive thing nirdep does and the reason it can be trusted to write.

And what an install weighs

A project that cannot run, then the same project running

Seven stages, recorded by running the real commands on a real temporary project. Nothing was installed in between, and nothing here is a screenshot: click a stage to read what it does and see exactly what it printed.

    
          

    Rewrite your own file

    This is not a mock-up. src/rules/rewrite.mjs, the lexer under it and the diff printer are all loaded into this page and run on the text below, the same way the CLI runs them on your disk. Edit it, break it, import something it refuses -- it will tell you which line and why.

    start from:
    
          
          

    The one thing this page cannot do: the CLI parses every rewritten file before it writes it, using node:vm, and a browser has no equivalent. So the diff above is real and the syntax gate is not run here. In the CLI, a file that would not parse is not written, and if any file fails the whole run writes nothing.

    Try the replacements

    Four of the five runtime modules, loaded from source and running here. Same functions the rewritten project imports; no shims around them except a fake filesystem for the glob walk, because a browser has no disk.

    semver

    Ranges, comparators, prereleases. Not one regular expression anywhere in it -- which is how the ReDoS class of bug stops being possible rather than being patched.

    
        

    glob

    Segment-by-segment matching with no backtracking, over the tree on the right. The walk is the real one; the filesystem under it is an object in this page.

    try src/**/!(*.test).mjs or {src,test}/**
    
        

    collect

    The subset people actually import: get, groupBy, isEqual, merge, cloneDeep, debounce. Own properties only, so a rewritten path cannot walk into a prototype.

    get, has, groupBy, keyBy, sortBy, uniqBy, chunk, isEqual, cloneDeep, merge, pick, omit
    
        

    colour

    Chalk's whole job is writing four bytes before your text and four after. Here are the bytes, spelled out, from the module that writes them.

    
        

    The fifth module, args, replaces minimist, commander and yargs. It reads process.argv, so there is nothing for it to read in a browser and no panel here pretends otherwise. nirdep --help is it, running.

    Why, and what it will not do

    The argument

    A dependency is not a library. It is a standing permission for somebody you have never met to run code on your machine, every install, forever. Most of the ones at the top of the list are doing something the standard library has done for years -- padding a string, comparing two version numbers, colouring a line of output.

    nirdep does not ask you to trust that argument. It shows you the imports, the blast radius, the diff, and the two packages it will not touch, and then you decide.

    The same bug, twice, in two packages

    semver and minimatch both had a denial-of-service bug of the identical shape: a regular expression that backtracks on input somebody else controls. Patching one version of that is a fix; removing the regular expression is the end of the class. Neither replacement here contains one, and the tests prove the answers still match, hundreds of thousands of comparisons at a time.

    lodash had two advisories of its own, one of which compiled its input into a function. The walkthrough's scan names all of them, per advisory, including the one against a package nirdep refuses to rewrite -- because that one is still in the lockfile afterwards.

    What is honest about this page

    • The walkthrough is a recording of a real run made when the page was built, colours and all. The counts, the diff and the error in stage 2 are what the commands printed.
    • The two sandboxes are not recordings. Eleven of nirdep's modules are embedded verbatim and loaded as ES modules; what they print is what they computed from your input.
    • The syntax gate needs node:vm, so it does not run here. In the CLI it runs on every file, and a run where one file fails writes none of them.
    • The glob panel walks a directory tree that is an object in this page. The traversal is the real one; six functions of node:fs, node:path and node:util are stood in for, and nothing else is.
    • No requests. This page works from a file:// URL, on a plane, forever.

    Run it on your own project

    No install step, because there is nothing to install: clone it and run node bin/nirdep.mjs. scan and plan only read. apply is the only command that writes, and guard is the one you put in CI so the packages you removed cannot come back in somebody's pull request.

    Words used on this page