A runtime-agnostic TypeScript library for parsing and validating VERS (VErsion Range Specifier) declarations.
vers-js provides a small, data-oriented API for canonical VERS syntax validation and parsed declaration metadata. It validates VERS strings like vers:npm/>=1.0.0|<2.0.0 and returns structured success/failure results with machine-readable diagnostics.
Key characteristics:
- Runtime-agnostic: Works in Node.js(>=22), Deno, and Bun
- Zero dependencies: No runtime dependencies
- ESM-only: Modern ECMAScript Modules, no CommonJS
- Named exports only: Explicit root exports with no JavaScript default export
- TypeScript-first: Written in TypeScript with full type declarations
- Strict canonical validation: No repair, coercion, or warning modes
- Machine-readable diagnostics: Structured error codes for downstream tooling
npm install @windlass/vers-js
# or
pnpm add @windlass/vers-js
# or
yarn add @windlass/vers-jsimport { parseVers, validateVers, canonicalizeVers } from "@windlass/vers-js";
// Parse a VERS declaration
const result = parseVers("vers:npm/>=1.0.0|<2.0.0");
if (result.ok) {
console.log(result.value.type); // "npm"
console.log(result.value.constraints); // parsed constraints
console.log(result.value.canonical); // canonical VERS string
} else {
console.log(result.issues); // structured diagnostics
}
// Validate without parsing
const valid = validateVers("vers:npm/>=1.0.0|<2.0.0");
// { ok: true, value: true }
// Get canonical form
const canonical = canonicalizeVers("vers:npm/>=1.0.0|<2.0.0");
// { ok: true, value: "vers:npm/>=1.0.0|<2.0.0" }Parses a VERS declaration and returns parsed syntax metadata.
Success:
{
ok: true,
value: {
scheme: "vers",
type: "npm",
constraints: [
{ comparator: ">=", version: "1.0.0" },
{ comparator: "<", version: "2.0.0" }
],
canonical: "vers:npm/>=1.0.0|<2.0.0"
}
}Validates a VERS declaration without returning parsed metadata.
Success: { ok: true, value: true }
Validates and returns the canonical VERS string.
Success: { ok: true, value: "vers:npm/>=1.0.0|<2.0.0" }
All three functions return discriminated Result types:
type VersResult<T> =
| { ok: true; value: T }
| { ok: false; issues: VersIssue[]; metadata?: VersFailureMetadata };Non-string inputs throw TypeError:
parseVers(null); // throws TypeError
validateVers(123); // throws TypeErrorIn scope (v0.1):
- Canonical VERS syntax validation
- Parsed declaration metadata (
VersRange,VersConstraint) - Canonical string projection
- Syntax-only type validation
- Single-pass percent-decoding
- Bounded diagnostics with original-input spans
Out of scope (v0.1):
- Version comparison or containment
- Native ecosystem range translation
- Semantic ordering or simplification
- Known-type registry enforcement
- Warning, repair, or coercion modes
- Vulnerability interpretation or VEX semantics
- Architecture Specifications: Implementation contracts and technical specifications
- Architectural Decision Records: Design decisions and rationale (MADR format)
- Release Process: Signed tag, npm Trusted Publishing, provenance, and GitHub Release workflow.
- Changelog: User-facing release notes maintained according to Keep a Changelog, with Human Era release dates.
- Contributing Guide: Organization-wide contribution process, PR expectations, and changelog workflow.
- Security Policy: Windlass organization-wide private vulnerability reporting, coordinated disclosure, and supply-chain integrity requirements.
- Code of Conduct: Contributor Covenant 3.0 community standards for all project interactions.
- AGENTS.md: Guidelines for AI assistants working in this repository
Prerequisites:
- Node.js 22 LTS or newer
- pnpm (package manager)
Scripts:
# Type checking
pnpm run typecheck # tsc --noEmit
# Building
pnpm run build # tsc -p tsconfig.build.json
# Testing
pnpm run test # vitest run
pnpm run test:pbt # vitest run tests/property-based.test.ts
pnpm run test:fuzz # per-property time-budgeted fuzz exploration
pnpm run test:watch # vitest
pnpm run test:coverage # vitest run --coverage
# test:fuzz applies its 10-second fast-check budget to each property test.
# Expected runtime is roughly: property count × 10 seconds, plus startup overhead.
# Replay a property failure with VERS_PBT_SEED=<seed> and VERS_PBT_PATH=<path>.
# Package verification (uses built artifacts)
pnpm run test:package # build and verify emitted package artifacts
pnpm run typecheck:package # build and type-check package consumer declarations
pnpm run typecheck:package:blocked # build and verify blocked subpath imports fail
pnpm run smoke:package # build and run package-name runtime smoke tests
pnpm run verify:package # run all package verification checks above
# Runtime smoke testing
pnpm run smoke:runtime # run built-package smoke tests under Node.js, Deno, and Bun
pnpm run verify:runtime # build, then run all runtime smoke tests
# Linting and formatting
pnpm run lint:md # markdownlint-cli2
pnpm run lint:ts # oxlint
pnpm run fmt # oxfmt
pnpm run fmt:check # oxfmt --checkApache 2.0. see LICENSE.