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

@visionary_software/contrax-range-check

v2026.5.10

Published

Contrax third-party plugin: InRange Enforcement + @rangeBounds JSDoc typedef registration.

Readme

contrax-range-check — Parameterized [lower, upper) Bounds Plugin (TypeScript line)

A third-party Enforcement for contrax that enforces numeric range constraints at compile time. Mirrors the Java line's InRange + @RangeBounds pair using JSDoc-typedef registration and JSON-shape bounds.

This is the TypeScript line. The Java line lives on java; the Kotlin K2/FIR port on kotlin.

Install

bun  add @visionary_software/contrax-range-check
npm  i   @visionary_software/contrax-range-check
pnpm add @visionary_software/contrax-range-check
yarn add @visionary_software/contrax-range-check

Direct dependency: @visionary_software/contrax-annotations for the Enforcement type, violate, and withDetail. Peer: typescript.

Usage

Pull the @rangeBounds typedef into your program by importing the package for its side effects (no runtime symbols are imported — only the source file's presence in the program matters), then annotate parameters or return values:

import "@visionary_software/contrax-range-check"; // makes @rangeBounds resolvable

class TemperatureSensor {
  /**
   * @postcondition InRange
   * @rangeBounds {"lower": -273, "upper": 1000}
   */
  readCelsius(): number {
    return this.celsius;
  }

  scoreEntry(/** @precondition InRange @rangeBounds {"lower": 0, "upper": 100} */ score: number): void {
    // …
  }
}

new TemperatureSensor().scoreEntry(150); // tsc ERROR: @rangeBounds violated at parameter #1 ('score' of type number) of TemperatureSensor.scoreEntry: 150 not in [0, 100)

API

InRange: Enforcement

Demands a value at the seam in the half-open interval [lower, upper). Three flavors of violation:

| Use site | Result | |---|---| | Literal null at a number \| null seam | Diagnostic with detail null literal | | Numeric literal at or above upper, or below lower | Diagnostic with detail <value> not in [lower, upper) | | Unary-minus over a numeric literal whose negation is out of range | Same frame |

Non-literal expressions (variables, computed values) pass silently — contrax is a compile-time framework and cannot reason about runtime values.

InRange throws on a misconfigured @rangeBounds tag (missing lower or upper) with the message:

@rangeBounds requires both 'lower' and 'upper' numeric attributes; got: <comment text>

Loud-on-misconfig, mirror of the Java line's IllegalStateException — the throw propagates out of the transformer and fails the build, which is the desired surface for a programmer error.

How @rangeBounds resolves

Two pieces collaborate to turn a use-site @rangeBounds tag into an InRange invocation:

  1. The package's src/index.ts declares a JSDoc typedef whose name is rangeBounds. The typedef itself is decorated with @contract, @precondition InRange, and @postcondition InRange — that meta-annotation block is what registers the use-site tag's enforcement policy.
  2. At every contrax-tagged use site, apt's tagsOnRegistrationSite primitive walks the program's source files looking for a typedef whose name matches the use-site tag. When the consumer's program contains range-check's source file (via the side-effect import), the walk finds the typedef and returns its tags; the dispatcher reads @precondition InRange, looks InRange up in the enforcements map, and invokes it with the use-site call site bound.

Without the side-effect import, no source file in the program declares @rangeBounds, the lookup returns the empty tag list, and use-site @rangeBounds tags silently no-op.

TypeScript peculiarities

  • Side-effect import is mandatory. Most TypeScript packages export named symbols you import { X } from "..."; this one is consumed purely for its side effects on the source-file set. The transformer's contract-discovery walks program.getSourceFiles(); the package's source file must be in that set or use-site tags silently no-op. import "@visionary_software/contrax-range-check" is the idiomatic way to pull a source file into the program's set without binding any runtime symbols. Tree-shaking is not a concern — the typedef block has no runtime payload, only AST contributions the transformer reads at build time.

  • CJS bundle ships alongside ESM. Same constraint as contrax-enforcements: the transformer's discovery does require() on the package.json#contrax.enforcements entry at build time, and Node's require cannot consume native ESM. So this package builds two artifacts — dist/index.js (ESM, what consumers import for the side effect) and dist/index.cjs (CJS, what the transformer loads at discovery time). If you fork this package or write your own typedef-bearing Enforcement bundle, you must publish both formats and point package.json#contrax.enforcements at the .cjs.

License

GPL-3.0-or-later. See COPYING. Contact Visionary Software Solutions for commercial licensing.