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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zero.sc/veil

v0.0.3

Published

Change or remove comments without touching code — a scanner that knows regex literals.

Readme


The problem this solves

Source comments say why the code is the way it is, which is exactly what makes them useful and exactly what makes some of them unpublishable. Internal ticket numbers, code names, rule numbers, paths on someone's machine, or simply a language your users do not read — all reasonable in a repository and none of it something you want inside a published artifact.

So you write a regex and run it over the file, and it eats your code. That is not hypothetical: a rule that removed empty parentheses from prose, applied file-wide, turned update: () => void into update: => void. The rule was fine. The scope was wrong.

Scoping to comments needs a scanner, and the naive scanner has a specific failure that is worse than not working — it works most of the time. It tracks quotes but not regex literals, so a line like /[&<>"']/g reads as the start of a string, and it loses sync for the rest of the file. Measured on one codebase: that single line hid sixteen comments in the file containing it, and a translation pipeline skipped that stretch entirely. Nobody noticed until one of those comments shipped.

Install

npm install @zero.sc/veil

No dependencies.

Sixty seconds

import { scanComments, scrubComments, stripComments } from '@zero.sc/veil';

// Where are the comments? Not the ones inside strings, templates or regexes.
scanComments(source);            // [{ kind: 'line', text, start, end }, …]

// Replace inside comments only — the same text in a string literal is left alone.
const { text, replaced } = scrubComments(source, [
  { pattern: /\bTICKET-\d+\b/g, replace: 'an internal ticket' },
]);

// Or remove them outright.
const cleaned = stripComments(source, (t) => /[^\x00-\x7F]/.test(t));

What's inside

| Export | What it does | |--------|--------------| | scanComments | Comment spans, aware of strings, templates and regex literals | | scrubComments | Replace inside comments only, back to front so spans stay valid | | stripComments | Remove matching comments and fold the blank line they leave | | codeOnly | Blank the comments, keep the line count — for checks that must tell inside from outside |

codeOnly is the one people do not expect to need until they do. Asking "does this file contain something shaped like a secret" gets a different answer for an example written in a comment than for a real value, and a check that cannot separate them either flags your documentation or misses the value. Blanking preserves offsets, so line numbers in the report still point at the right place.

How division is told from regex

There is no full parser here. / is division when the preceding token ends a value — an identifier, a number, ), ], } — and a regex otherwise, with an exception list for keywords that end a value shape but precede a regex (return, typeof, throw, case, yield, await and the rest).

That heuristic is what real tokenisers use short of parsing, and the important property is the direction it fails in: when it guesses wrong it finds fewer comments. It never mistakes code for a comment, so it never edits code.

Honest limits

  • Heuristic, not a parser. See above. Exotic code can hide a comment from it; it cannot make it damage code.
  • JavaScript-family syntax. TypeScript, JSX and CSS (with lineComments: false) work. Python, Ruby and shell do not — their comment and string rules are different.
  • Template expressions are skipped whole. A comment inside ${…} is not reported. It belongs to an expression, not to the file's narration.
  • No JSDoc structure. Comments come back as text. Parsing tags is somebody else's job.
  • This is 0.0.x.

Around it

| | | |---|---| | Docs | kit.zero.sc | | Small functions | @zero.sc/util | | Everything | @zero.sc |

License

MIT OR Zero License v1.0 — take whichever you prefer. Choosing MIT is enough; nothing further is required of you.

The Zero name, marks and logos are not covered — build anything you like with this code, just don't present it as a Zero product.

Copyright (c) 2026 Zero. Source Code begins at Zero.