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

@computerwwwizards/version-inferer

v0.0.1

Published

A flexible, source-agnostic library for inferring and resolving configuration values from multiple sources with configurable precedence and conflict handling strategies

Readme

Version Inferers

A flexible, source-agnostic library for inferring and resolving configuration values from multiple sources with configurable precedence and conflict handling strategies.

🎯 Purpose

This library solves the common problem of determining which version or configuration value to use when multiple sources provide conflicting information. Originally designed for Node.js version inference, it has evolved into a generic resolution system applicable to any scenario requiring multi-source orchestration.

Real-world Use Cases

  • 🔧 Node.js Version Management: Automatically detect the correct Node.js version from .nvmrc, package.json, or CI/CD workflows
  • ⚙️ Configuration Resolution: Resolve settings from environment files, config files, and defaults with clear precedence rules
  • 🚀 CI/CD Integration: Ensure your local environment matches your deployment configuration
  • 🔄 Monorepo Management: Coordinate versions across multiple packages and workspaces

✨ Key Features

  • 🔌 Pluggable Sources: Register any number of custom or built-in sources
  • 📊 Configurable Precedence: Define resolution order at runtime
  • ⚠️ Conflict Strategies: Choose how to handle conflicting values (report, error, or use first)
  • 🌊 Stream-based: Efficient file reading with proper resource cleanup
  • 📦 Type-safe: Full TypeScript support with generic types
  • 🧩 Extensible: Easy to add new source types and strategies

🚀 Quick Start

Installation

pnpm install @computerwwwizards/version-inferer

Basic Usage

import inferNodeVersion from '@computerwwwizards/version-inferer';

// Infer Node.js version from project files
const result = await inferNodeVersion();
console.log(`Use Node.js ${result.version}`);

📚 Examples

Example 1: Simple Node Version Detection

Automatically detects Node version from .nvmrc or package.json:

import inferNodeVersion from '@computerwwwizards/version-inferer';

const result = await inferNodeVersion({
  rootPath: '/path/to/project'
});

if (result.version) {
  console.log(`✅ Node version: ${result.version}`);
} else {
  console.log('❌ No version found');
}

// Result includes all checked sources
console.log('Checked sources:', result.data);
// { nvmrc: '20.0.0', 'package.json': null }

Example 2: Include CI/CD Workflow Configuration

Check GitHub Actions workflow files for Node version:

import inferNodeVersion from '@computerwwwizards/version-inferer';

const result = await inferNodeVersion({
  workflowFilePath: '.github/workflows/ci.yml',
  workflowOption: ['jobs', 'test', 'steps', '0', 'with', 'node-version'],
  rootPath: process.cwd()
});

console.log('Version from CI:', result.version);

Example 3: Custom Precedence Order

Prioritize specific sources over others:

import inferNodeVersion, { ConflictStrategy } from '@computerwwwizards/version-inferer';

const result = await inferNodeVersion({
  workflowFilePath: '.github/workflows/deploy.yml',
  workflowOption: ['jobs', 'deploy', 'with', 'node-version'],
  // Prioritize workflow, then package.json, then .nvmrc
  order: ['workflow', 'package.json', 'nvmrc'],
  conflictStrategy: ConflictStrategy.STOP_ON_FIRST
});

console.log(`Using: ${result.version}`);

Example 4: Handle Version Conflicts

Different strategies for handling conflicting versions:

import inferNodeVersion, { ConflictStrategy } from '@computerwwwizards/version-inferer';

// Strategy 1: Report conflicts but continue
const result1 = await inferNodeVersion({
  conflictStrategy: ConflictStrategy.REPORT
});

if (result1.conflicts.length > 0) {
  console.log('⚠️  Version conflicts detected:');
  result1.conflicts.forEach(conflict => {
    console.log(`  ${conflict.sources.join(' vs ')}: ${conflict.values.join(' vs ')}`);
  });
}

// Strategy 2: Throw error on conflict
try {
  const result2 = await inferNodeVersion({
    conflictStrategy: ConflictStrategy.ERROR
  });
} catch (error) {
  console.error('Version conflict error:', error.message);
}

// Strategy 3: Stop at first valid version (default)
const result3 = await inferNodeVersion({
  conflictStrategy: ConflictStrategy.STOP_ON_FIRST
});
console.log('First valid version:', result3.version);

Example 5: Advanced - Custom Version Sources

Build your own resolver with custom sources:

import VersionPrecedenceResolver from '@computerwwwizards/version-inferer';

const resolver = new VersionPrecedenceResolver();

// Add custom sources
resolver
  .registerSource('envVar', async () => process.env.NODE_VERSION || null)
  .registerSource('defaultConfig', async () => '18.0.0')
  .registerSource('userPreference', {
    getVersion: async () => {
      // Read from database, API, etc.
      return '20.0.0';
    }
  });

const result = await resolver.resolveVersion({
  order: ['userPreference', 'envVar', 'defaultConfig']
});

console.log('Resolved version:', result.version);

Example 6: CI/CD Integration Script

Create a script to ensure environment matches CI:

#!/usr/bin/env node
import inferNodeVersion from '@computerwwwizards/version-inferer';
import { execSync } from 'child_process';

async function ensureNodeVersion() {
  const result = await inferNodeVersion({
    workflowFilePath: '.github/workflows/ci.yml',
    workflowOption: ['jobs', 'test', 'strategy', 'matrix', 'node-version', '0'],
    order: ['workflow', 'nvmrc', 'package.json']
  });

  if (!result.version) {
    console.error('❌ No Node version specified');
    process.exit(1);
  }

  const currentVersion = execSync('node -v').toString().trim();
  const requiredVersion = `v${result.version}`;

  if (currentVersion !== requiredVersion) {
    console.log(`⚠️  Version mismatch: ${currentVersion} !== ${requiredVersion}`);
    console.log(`Run: nvm use ${result.version}`);
    process.exit(1);
  }

  console.log(`✅ Using correct Node version: ${currentVersion}`);
}

ensureNodeVersion();

🏗️ Architecture

Built-in Sources

  • NvmrcStreamSource: Reads .nvmrc files
  • PackageJsonStreamSource: Extracts engines.node from package.json
  • CiYamlStreamSource: Parses YAML files (GitHub Actions, GitLab CI, etc.)

Conflict Strategies

| Strategy | Behavior | |----------|----------| | STOP_ON_FIRST | Returns first non-null value (default) | | REPORT | Collects conflicts but continues resolution | | ERROR | Throws error if conflicts detected |

Stream Factory Pattern

All sources use a factory pattern to ensure proper resource management:

import { createReadStream } from 'fs';
import { NvmrcStreamSource } from '@computerwwwizards/version-inferer';

// ✅ Good: Stream created on-demand and auto-cleaned
const source = new NvmrcStreamSource(() => createReadStream('.nvmrc'));

// ❌ Bad: Pre-created stream may leak or lock
const stream = createReadStream('.nvmrc');
const source = new NvmrcStreamSource(stream); // Old API

🔮 Future Directions

This library is evolving toward:

  • Multi-value Resolution: Support for resolving multiple related values (Node + npm versions)
  • Caching Strategies: Optional caching for expensive source reads
  • Validation Rules: Built-in version constraint validation
  • Plugin System: Marketplace for community-contributed sources
  • Language Agnostic: Extend to Python, Ruby, Java version management
  • Web API: REST interface for version resolution services

🛠️ Development

Setup

Install dependencies:

pnpm install

Build

pnpm build

Development (watch mode)

pnpm dev

Run Tests

pnpm test

Format Code

pnpm format

📖 API Reference

inferNodeVersion(options?)

Main function for Node.js version inference.

Options:

{
  workflowFilePath?: string;        // Path to CI/CD workflow file
  workflowOption?: string[];        // YAML path to version field
  rootPath?: string;                // Project root (default: process.cwd())
  order?: string[];                 // Source precedence order
  conflictStrategy?: ConflictStrategy; // How to handle conflicts
}

Returns: Promise<ResolveResult>

{
  version: string | null;           // Resolved version
  data: Record<string, string | null>; // All source values
  conflicts: Conflict[];            // Detected conflicts
}

VersionPrecedenceResolver

Generic resolver class for custom implementations.

See Precedence Resolver Documentation for detailed architecture and design decisions.

📄 License

MIT License - see the LICENSE file for details.

Copyright (c) 2025 ComputerWWWizards

🤝 Contributing

Contributions welcome! Please read our contributing guidelines before submitting PRs.