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

dts-nano

v0.2.0

Published

TypeScript declaration and JSDoc parser built with Nanolex

Readme

dts-parser

Install the npm package with npm install dts-nano.

src/declarations.ts expresses declaration, type, member, expression and JSDoc productions with Nanolex's and, or, rule, peek, not, repetition, optional rules and AST transforms. There is no recursive-descent declaration parser or TypeScript compiler dependency.

A separate lexer uses SourceCursor and sourcePattern to preserve trivia, Unicode offsets, line breaks and context-sensitive template token boundaries. Token text and source metadata are stored in parallel arrays. The SOURCE entry rule adapts those lexemes to Nanolex's Context; small terminal predicates read token categories, line breaks and single-token type boundaries, and a mapped span transform attaches source metadata. These adapters do not recognize declarations or recursive types. Expression precedence is composed from grammar rules and AST folds. Conditional-type contexts use separate recursive rules, without mutable grammar flags. JSDoc uses combinator grammars for tags, links and balanced type annotations, followed by field normalization. The parser does not import the TypeScript compiler.

import { parseDeclarations } from "dts-nano";

const file = parseDeclarations(`
/** A named collection. */
export interface Collection<T> {
  readonly values: T[];
  map<U>(fn: (value: T) => U): Collection<U>;
}
`);
const declaration = file.children[0];
console.log(declaration.kind, declaration.name, declaration.docs);

The result contains the complete source, ordered declaration children, comments, and UTF-16 [start, end) offsets. Each node has a syntax kind and ordered children; names, modifiers, operators, optional markers and rest markers have separate fields. Types are recursive nodes, including conditional branches, union/intersection precedence, indexed access, templates, mapped types and function/constructor signatures. Names and list helper nodes are deliberately simpler than the compiler AST. The tree does not retain parent pointers.

JSDoc is attached to the following declaration/member/parameter and also retained in the file's comment list. Documentation includes the original text and span, description, ordered tags, inline links, parameter names, optional/default values, and balanced type annotation text. Unknown tags are preserved. Fenced examples remain prose. JSDoc type annotations retain their spelling, including Closure syntax; they are not type-checked or resolved. Triple-slash directives include their names and quoted attributes. Ordinary comments are preserved too.

Parsing consumes the entire file and fails with an offset and expectation on unrecognized syntax. It does not silently fall back to opaque balanced blocks. This is syntax parsing, not a type checker: it does not resolve imports or triple-slash references, merge declarations, check ambient semantic restrictions, or execute implementations. Call it for each source file in a library.

References

The grammar was developed from these primary references:

The archived specification predates modern TypeScript. The current handbook and compiler AST comparisons cover the newer forms; the old grammar alone is not a complete declaration-language specification.

Running the checks

npm ci
npm test

The lockfile supplies real published declarations. The corpus recursively reads all .d.ts, .d.mts and .d.cts files from TypeScript, React, Exome, Vue and its component packages, plus Node, Babel and csstype. TypeScript 6 is installed under typescript-reference for its compiler API, and TypeScript 7 under typescript-current to exercise its bundled declarations without changing the package's existing TypeScript build toolchain.

Corpus checks compare complete-file consumption, top-level statement counts and boundaries, recursive type/declaration kinds and spans, child containment, and preservation of compiler-recognized JSDoc. Focused tests check the resulting tree, precedence, modern syntax, documentation fields, source fidelity and malformed inputs. Package releases are finite regression fixtures, not proof of perfection for all future TypeScript syntax. Update the pinned corpus and extend the grammar when a new declaration construct appears.

Performance checks

Run npm run bench:typescript for warmed, parse-only medians over the same pinned corpus used by the correctness tests. File discovery and reads happen before timing. The corpus uses 3 warmups and 10 measured runs; DOM, React and Vue runtime-core use 5 warmups and 20 runs each. Each JSON output row includes file count, input bytes, repeat counts and median milliseconds. Compare runs on the same machine and runtime without concurrent CPU-heavy work.

The grammar compiles its declaration and JSDoc combinators with Nanolex. The compiler generates JavaScript from the grammar; it does not substitute a handwritten declaration parser. Compilation happens once before warmed timing, requires dynamic code generation, and leaves the library interpreter as the default for other consumers.

The grammar uses lookahead dispatch and single token matches for keyword sets and reuses child AST nodes when a precedence level has no operator. JSDoc avoids additional parser passes for text without a possible link or leading type annotation. Nanolex's sequence combinator skips value-array allocation when its first rule fails; alternatives and optional rules forward untransformed results without extra result tuples. These optimizations retain the combinator grammar and its backtracking behavior.

Standalone package

Run npm ci and npm run build:lib to produce the bundled ESM parser and TypeScript declarations. The existing package name is dts-nano. Import parseDeclarations or parseJSDoc from the package entry point. The parser is synchronous and throws on malformed declarations.

Extracted from Nanolex commit 194e5ec51e7f7e5794b59ef3638de8eefbf9c025. Its compiler, dispatch and fold APIs are not in npm's Nanolex 0.9.0 release. For reproducible builds, nanolex-source pins that revision’s source archive as a development dependency; TypeScript and esbuild resolve its source explicitly. Deno tests fetch the same revision from GitHub, verified by deno.lock. The distributed JavaScript bundles Nanolex, so consumers do not need Git or source resolution. Replace this build dependency with a published Nanolex release once those APIs ship. Nanolex's MIT license is retained.

The experimental playground (npm run app) still uses src/parser.ts and its legacy AST/Markdown renderer. It is not the new public parser. Its old sample script is preserved in examples/legacy.ts. The public entry point has no demo side effects.

Releases

The Publish workflow publishes the package when a GitHub release is published. Configure npm trusted publishing for package dts-nano, GitHub owner Marcisbee, repository dts-parser, and workflow publish.yml (no environment). The workflow can also be dispatched manually to retry an unpublished version. Version changes must be committed before tagging the release.