CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pnpm--npm-resolver

Resolver for npm-hosted packages with caching, offline support, and registry authentication

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

version-selection.mddocs/

Version Selection

The version selection system handles intelligent package version resolution based on preferences, constraints, and semantic versioning rules with support for tags, ranges, and exact versions.

Capabilities

Package Specification Types

Core types used for version resolution within the resolver.

/**
 * Structured package specification for version resolution
 */
interface RegistryPackageSpec {
  /** Type of specification */
  type: 'tag' | 'version' | 'range';
  /** Package name */
  name: string;
  /** Specification string to match against */
  fetchSpec: string;
  /** Normalized preference for caching */
  normalizedPref?: string;
}

Version Preference Configuration

Configure preferred versions for specific packages during resolution.

/**
 * Version preference configuration for specific packages
 */
interface PreferredVersions {
  [packageName: string]: {
    /** Version selector (exact version, range, or tag) */
    selector: string;
    /** Type of version selector */
    type: 'version' | 'range' | 'tag';
  };
}

/**
 * Options for package resolution
 */
interface ResolveOptions {
  /** Default tag when no preference specified */
  defaultTag?: string;
  /** Registry URL to resolve from */
  registry: string;
  /** Preferred versions for specific packages */
  preferredVersions?: PreferredVersions;
  /** Project root prefix */
  prefix: string;
  /** Available local packages for fallback */
  localPackages?: LocalPackages;
}

Package Selection Logic

The resolver internally handles package version selection from metadata based on the specification type and preferred versions configuration. This process is handled automatically when calling the resolver function.

Usage Examples

Basic Version Selection

import createResolveFromNpm from '@pnpm/npm-resolver';

const resolve = createResolveFromNpm({
  metaCache: new Map(),
  store: './pnpm-store',
  rawNpmConfig: { registry: 'https://registry.npmjs.org/' },
});

// Exact version
const exactResult = await resolve(
  { alias: 'lodash', pref: '4.17.21' },
  { 
    registry: 'https://registry.npmjs.org/',
    prefix: process.cwd()
  }
);

// Semantic version range
const rangeResult = await resolve(
  { alias: 'express', pref: '^4.18.0' },
  { 
    registry: 'https://registry.npmjs.org/',
    prefix: process.cwd()
  }
);

// Tag-based selection
const tagResult = await resolve(
  { alias: 'react', pref: 'beta' },
  { 
    registry: 'https://registry.npmjs.org/',
    prefix: process.cwd()
  }
);

console.log(`Exact: ${exactResult?.package.version}`);
console.log(`Range: ${rangeResult?.package.version}`);  
console.log(`Tag: ${tagResult?.package.version}`);

Advanced Range Selection

// Complex version ranges
const complexRanges = [
  { alias: 'typescript', pref: '~4.9.0' },      // Patch-level changes
  { alias: 'webpack', pref: '^5.0.0' },         // Compatible changes
  { alias: 'eslint', pref: '>=8.0.0 <9.0.0' },  // Range with constraints
  { alias: 'prettier', pref: '2.x' },           // Major version wildcard
];

for (const dep of complexRanges) {
  const result = await resolve(dep, { 
    registry: 'https://registry.npmjs.org/',
    prefix: process.cwd()
  });
  
  if (result) {
    console.log(`${dep.alias}@${dep.pref} -> ${result.package.version}`);
  }
}

Preferred Version Configuration

// Configure preferred versions for specific packages
const preferredVersions = {
  'react': {
    selector: '17.0.2',  // Prefer specific stable version
    type: 'version' as const
  },
  'lodash': {
    selector: '^4.17.0', // Prefer range within 4.17.x
    type: 'range' as const
  },
  'typescript': {
    selector: 'beta',     // Prefer beta releases
    type: 'tag' as const
  }
};

const result = await resolve(
  { alias: 'react', pref: '^17.0.0' },
  { 
    registry: 'https://registry.npmjs.org/',
    prefix: process.cwd(),
    preferredVersions
  }
);

// Will prefer 17.0.2 even though range allows newer versions
console.log(`Selected version: ${result?.package.version}`);

Custom Tag Handling

// Working with distribution tags
const tagExamples = [
  { alias: 'next', pref: 'canary' },     // Canary releases
  { alias: 'vue', pref: 'beta' },        // Beta releases  
  { alias: 'angular', pref: 'next' },    // Next major version
  { alias: 'react', pref: 'experimental' }, // Experimental features
];

for (const dep of tagExamples) {
  try {
    const result = await resolve(dep, { 
      registry: 'https://registry.npmjs.org/',
      prefix: process.cwd()
    });
    
    if (result) {
      console.log(`${dep.alias}@${dep.pref}: ${result.package.version}`);
      console.log(`Latest: ${result.latest}`);
    }
  } catch (error) {
    console.error(`Tag ${dep.pref} not found for ${dep.alias}`);
  }
}

Fallback Strategy

// Try multiple version preferences with fallback
async function resolveWithFallback(packageName: string, preferences: string[]) {
  for (const pref of preferences) {
    try {
      const result = await resolve(
        { alias: packageName, pref },
        { 
          registry: 'https://registry.npmjs.org/',
          prefix: process.cwd()
        }
      );
      
      if (result) {
        console.log(`Resolved ${packageName}@${pref} -> ${result.package.version}`);
        return result;
      }
    } catch (error) {
      console.log(`Failed to resolve ${packageName}@${pref}: ${error.message}`);
    }
  }
  
  throw new Error(`Could not resolve ${packageName} with any preference`);
}

// Try beta first, fallback to latest
const result = await resolveWithFallback('typescript', ['beta', 'rc', 'latest']);

Version Format Support

The resolver supports various version specification formats:

// Different preference formats supported
const supportedFormats = [
  '1.2.3',           // Exact version
  '^1.2.0',          // Caret range - compatible within major version
  '~1.2.0',          // Tilde range - compatible within minor version
  '>=1.0.0 <2.0.0',  // Range expression with constraints
  'latest',          // Distribution tag
  'beta',            // Beta distribution tag
  'next',            // Next distribution tag
];

// Example resolution with different formats
for (const pref of supportedFormats) {
  const result = await resolve(
    { alias: 'example-package', pref },
    { 
      registry: 'https://registry.npmjs.org/',
      prefix: process.cwd()
    }
  );
  
  if (result) {
    console.log(`"${pref}" resolved to: ${result.package.version}`);
  }
}

Local Package Integration

// Define local packages for development
const localPackages = {
  'my-lib': {
    '1.0.0': {
      directory: '/workspace/my-lib',
      package: { name: 'my-lib', version: '1.0.0' }
    },
    '1.1.0-dev': {
      directory: '/workspace/my-lib',
      package: { name: 'my-lib', version: '1.1.0-dev' }
    }
  }
};

// Prefer local development version over registry
const devResult = await resolve(
  { alias: 'my-lib', pref: '^1.0.0' },
  { 
    registry: 'https://registry.npmjs.org/',
    prefix: process.cwd(),
    localPackages
  }
);

if (devResult?.resolvedVia === 'local-filesystem') {
  console.log(`Using local development version: ${devResult.package.version}`);
  console.log(`Location: ${devResult.resolution.directory}`);
} else {
  console.log(`Using registry version: ${devResult?.package.version}`);
}

Version Preference Validation

// Validate version preferences through resolution attempt
async function validateVersionPreference(alias: string, pref: string): Promise<boolean> {
  try {
    const result = await resolve(
      { alias, pref },
      { 
        registry: 'https://registry.npmjs.org/',
        prefix: process.cwd()
      }
    );
    
    return result !== null;
  } catch (error) {
    // Invalid preference or resolution failed
    return false;
  }
}

// Test various preferences
const testPreferences = [
  { alias: 'lodash', pref: '4.17.21' },  // Valid exact version
  { alias: 'lodash', pref: '^4.0.0' },   // Valid range
  { alias: 'lodash', pref: 'latest' },   // Valid tag
  { alias: 'lodash', pref: 'invalid' },  // Invalid tag
];

for (const { alias, pref } of testPreferences) {
  const isValid = await validateVersionPreference(alias, pref);
  console.log(`${alias}@${pref}: ${isValid ? 'valid' : 'invalid'}`);
}

Install with Tessl CLI

npx tessl i tessl/npm-pnpm--npm-resolver

docs

index.md

metadata-management.md

package-resolution.md

version-selection.md

tile.json