or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

parsing.mddocs/reference/

Lockfile Parsing

The ParseLockfile class provides functionality to parse npm and yarn lockfiles into a unified format for validation. It supports multiple lockfile formats including npm v1/v2/v3, npm-shrinkwrap.json, yarn classic (v1), and Yarn Berry (v2+).

Capabilities

ParseLockfile Constructor

Creates a new lockfile parser instance.

/**
 * Creates a new lockfile parser
 * @param {Object} options - Parser configuration
 * @param {string} [options.lockfilePath] - Path to the lockfile (absolute or relative)
 * @param {string} [options.lockfileText] - UTF-8 string content of the lockfile
 * @param {string} [options.lockfileType] - Package manager type: 'npm', 'npmjs', 'yarn', or 'yarnpkg'
 * @throws {ParsingError} If neither lockfilePath nor lockfileText is provided
 */
class ParseLockfile {
  constructor(options: {
    lockfilePath?: string;
    lockfileText?: string;
    lockfileType?: string;
  });
}

Requirements: Either lockfilePath or lockfileText must be provided. If neither is provided, a ParsingError with type NO_LOCKFILE will be thrown.

Usage Examples:

const { ParseLockfile } = require('lockfile-lint-api');

// Parse from file path
const parser1 = new ParseLockfile({
  lockfilePath: './package-lock.json'
});

// Parse from string content
const fs = require('fs');
const content = fs.readFileSync('./yarn.lock', 'utf-8');
const parser2 = new ParseLockfile({
  lockfileText: content
});

// Specify lockfile type explicitly
const parser3 = new ParseLockfile({
  lockfilePath: './custom.lock',
  lockfileType: 'yarn'
});

// Error: Missing both options
try {
  const parser4 = new ParseLockfile({});
} catch (error) {
  // error.name === 'ParsingError'
  // error.message includes 'NO_LOCKFILE'
}

Parse Synchronously

Parses the lockfile synchronously and returns the parsed result.

/**
 * Synchronously parses the lockfile
 * @returns {Object} Parsed lockfile with type and object properties
 * @throws {ParsingError} If parsing fails or file cannot be read
 */
parseSync(): {
  type: 'success';
  object: {
    [packageKey: string]: {
      version: string;
      resolved?: string;
      integrity?: string;
      requires?: Object;
    };
  };
}

The returned object has the following structure:

  • type: Always 'success' if parsing succeeds
  • object: A map of package keys to package metadata

Package keys are formatted as: package-name@version-hash for npm lockfiles, or package-name@version-range for yarn lockfiles.

Usage Examples:

const { ParseLockfile } = require('lockfile-lint-api');

try {
  const parser = new ParseLockfile({
    lockfilePath: './package-lock.json'
  });
  const result = parser.parseSync();

  console.log(result.type); // 'success'
  console.log(Object.keys(result.object).length); // Number of packages

  // Iterate through packages
  for (const [packageKey, metadata] of Object.entries(result.object)) {
    console.log(`Package: ${packageKey}`);
    console.log(`  Version: ${metadata.version}`);
    console.log(`  Resolved: ${metadata.resolved}`);
    console.log(`  Integrity: ${metadata.integrity}`);
  }
} catch (error) {
  if (error.name === 'ParsingError') {
    console.error('Failed to parse lockfile:', error.message);
  }
}

Check if Lockfile Type is Given

Helper method to check if lockfile type was explicitly provided.

/**
 * Checks if lockfileType option was provided
 * @returns {boolean} True if lockfileType was specified
 */
isLockfileTypeGiven(): boolean;

Usage:

const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
if (parser.isLockfileTypeGiven()) {
  console.log('Lockfile type was explicitly set');
} else {
  console.log('Lockfile type will be auto-detected');
}

Resolve Package Manager for Lockfile

Determines the appropriate parser based on lockfile type or filename.

/**
 * Resolves the appropriate parser for the lockfile
 * @returns {Function} Parser function for the detected lockfile type
 * @throws {ParsingError} If parser cannot be determined
 */
resolvePkgMgrForLockfile(): Function;

Resolve Package Manager by Filename

Determines parser based solely on filename.

/**
 * Determines parser based on filename
 * @returns {Function} Parser function or undefined if not recognized
 */
resolvePkgMgrByFilename(): Function | undefined;

Recognized filenames:

  • package-lock.json → npm parser
  • yarn.lock → yarn parser

Note: npm-shrinkwrap.json files are NOT auto-detected by filename. To parse npm-shrinkwrap.json files, you must explicitly specify lockfileType: 'npm' in the constructor options.

Parse Yarn Lockfile

Parses a Yarn lockfile (both classic and Berry formats).

/**
 * Parses Yarn lockfile format
 * @param {string|Buffer} lockfileBuffer - The lockfile contents
 * @returns {Object} Parsed lockfile result
 * @throws {ParsingError} If parsing fails
 */
parseYarnLockfile(lockfileBuffer: string | Buffer): {
  type: 'success';
  object: Object;
}

Parse npm Lockfile

Parses an npm lockfile (v1, v2, or v3 format).

/**
 * Parses npm lockfile format (package-lock.json or npm-shrinkwrap.json)
 * @param {string|Buffer} lockfileBuffer - The lockfile contents
 * @returns {Object} Parsed lockfile result
 * @throws {ParsingError} If parsing fails
 */
parseNpmLockfile(lockfileBuffer: string | Buffer): {
  type: 'success';
  object: Object;
}

Extract Package Name

Extracts clean package name from node_modules path.

/**
 * Extracts package name from full path
 * @param {string} packageName - Full package path (may include node_modules/)
 * @returns {string} Clean package name
 */
extractedPackageName(packageName: string): string;

Usage Examples:

const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });

// Extract clean package names
console.log(parser.extractedPackageName('node_modules/lodash'));
// Output: 'lodash'

console.log(parser.extractedPackageName('node_modules/@babel/core'));
// Output: '@babel/core'

console.log(parser.extractedPackageName('packages/app/node_modules/react'));
// Output: 'react'

Lockfile Format Support

npm Lockfile Formats

The parser handles multiple npm lockfile formats:

  1. npm v1/v2 (package-lock.json): Uses dependencies field with nested structure
  2. npm v3 (package-lock.json): Uses packages field with flat structure
  3. npm-shrinkwrap.json: Same format as package-lock.json (requires explicit lockfileType: 'npm' parameter)

Yarn Lockfile Formats

  1. Yarn Classic (v1): Traditional yarn.lock format with SYML syntax
  2. Yarn Berry (v2+): Modern format with __metadata field and resolution syntax

Yarn Berry lockfiles are automatically normalized to match the classic format's structure for consistent validation.

Error Handling

ParsingError

The parser throws ParsingError for critical failures:

class ParsingError extends Error {
  constructor(errorFn: Function, relatedValue?: string, error?: Error);
  name: 'ParsingError';
  message: string;
  stack: string;
}

Error Types:

  • NO_OPTIONS: Constructor called without options object
  • NO_LOCKFILE: Neither lockfilePath nor lockfileText provided
  • NO_PARSER_FOR_TYPE: Unsupported lockfile type specified
  • NO_PARSER_FOR_PATH: Cannot determine lockfile type from filename
  • READ_FAILED: Cannot read lockfile from filesystem
  • PARSE_NPMLOCKFILE_FAILED: npm lockfile parsing failed (invalid JSON or format)
  • PARSE_YARNLOCKFILE_FAILED: yarn lockfile parsing failed (invalid SYML or format)

Usage Examples:

const { ParseLockfile } = require('lockfile-lint-api');

try {
  const parser = new ParseLockfile({
    lockfilePath: './unknown.lock'
  });
  const result = parser.parseSync();
} catch (error) {
  if (error.name === 'ParsingError') {
    console.error('Parsing error:', error.message);
    // Example messages:
    // "Unable to find relevant lockfile parser for "unknown.lock", consider passing the --type option."
    // "Unable to parse npm lockfile "./package-lock.json""
  } else {
    console.error('Unexpected error:', error);
  }
}

Package Metadata Structure

After parsing, each package entry contains:

interface PackageMetadata {
  version: string;           // Exact version installed
  resolved?: string;         // URL where package was downloaded from
  integrity?: string;        // Integrity hash (usually sha512-...)
  requires?: Object;         // Map of dependency names to version ranges
}

Notes:

  • resolved field may be missing for packages installed from local filesystem
  • integrity field may be missing for older lockfile formats or git dependencies
  • Package keys include version and hash information for uniqueness

Auto-Detection Logic

When lockfileType is not specified, the parser uses this auto-detection logic:

  1. If lockfilePath ends with package-lock.json → npm parser
  2. If lockfilePath ends with yarn.lock → yarn parser
  3. If lockfileType is 'npm' or 'npmjs' → npm parser
  4. If lockfileType is 'yarn' or 'yarnpkg' → yarn parser
  5. Otherwise → throw ParsingError with type NO_PARSER_FOR_PATH

Best Practice: For non-standard filenames, always specify lockfileType explicitly.

Edge Cases

Handling Missing Fields

// Packages without resolved field (local filesystem)
{
  'local-package@1.0.0': {
    version: '1.0.0'
    // No resolved field
  }
}

// Packages without integrity (git dependencies, old lockfiles)
{
  'git-package@1.0.0': {
    version: '1.0.0',
    resolved: 'git+https://github.com/user/repo.git'
    // No integrity field
  }
}

Handling Multiple Lockfile Versions

// npm v1/v2 format detection
const parser = new ParseLockfile({
  lockfilePath: './package-lock.json',
  lockfileType: 'npm'
});
// Automatically detects v1/v2 vs v3 format

// Yarn Berry detection
const parser = new ParseLockfile({
  lockfilePath: './yarn.lock',
  lockfileType: 'yarn'
});
// Automatically detects classic vs Berry format

Error Recovery Patterns

function safeParseLockfile(path, type) {
  try {
    const parser = new ParseLockfile({
      lockfilePath: path,
      lockfileType: type
    });
    return parser.parseSync();
  } catch (error) {
    if (error.name === 'ParsingError') {
      // Handle parsing-specific errors
      if (error.message.includes('NO_PARSER_FOR_PATH')) {
        // Try with explicit type
        return safeParseLockfile(path, 'npm');
      }
    }
    throw error;
  }
}