CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-resolve

Resolve like require.resolve() on behalf of files asynchronously and synchronously

Pending
Overview
Eval results
Files

sync-resolution.mddocs/

Synchronous Resolution

Synchronous module resolution that implements the Node.js require.resolve() algorithm without callbacks, throwing errors instead of passing them to callback functions. Ideal for build-time processing and initialization scenarios.

Capabilities

Resolve Sync Function

Main synchronous resolution function that resolves module path strings into absolute file paths.

/**
 * Synchronously resolve module path string
 * @param {string} id - Module path string to resolve
 * @param {object} [options] - Resolution options
 * @returns {string} Resolved absolute path to the module
 * @throws {Error} Resolution or validation errors
 */
function resolveSync(id, options);

Usage Examples:

const resolve = require('resolve');

// Basic resolution
try {
  const res = resolve.sync('lodash', { basedir: __dirname });
  console.log(res); // /path/to/node_modules/lodash/index.js
} catch (err) {
  console.error('Resolution failed:', err.message);
}

// Relative path resolution
const helperPath = resolve.sync('./utils/helper', { 
  basedir: '/project/src',
  extensions: ['.js', '.json']
});
console.log(helperPath); // /project/src/utils/helper.js

// Alternative import method
const resolveSync = require('resolve/sync');
const modulePath = resolveSync('express', { basedir: __dirname });

Resolution Options

Basic Configuration

interface SyncResolveOptions {
  /** Directory to begin resolving from (default: dirname of calling file) */
  basedir?: string;
  /** File extensions to search in order (default: ['.js']) */
  extensions?: string[];
  /** Include Node.js core modules in search (default: true) */
  includeCoreModules?: boolean;
  /** Don't resolve basedir to real path before resolving (default: true) */
  preserveSymlinks?: boolean;
  /** Directory names to search for modules (default: 'node_modules') */
  moduleDirectory?: string | string[];
}

File System Options

Custom synchronous file system operations for testing, virtualization, or alternative storage backends.

interface SyncFileSystemOptions {
  /** Custom sync file reading function */
  readFileSync?: (file: string) => Buffer | string;
  /** Custom sync file existence test function */
  isFile?: (file: string) => boolean;
  /** Custom sync directory existence test function */
  isDirectory?: (dir: string) => boolean;
  /** Custom sync symlink resolution function */
  realpathSync?: (path: string) => string;
}

Usage Example:

const fs = require('fs');
const resolve = require('resolve');

const res = resolve.sync('custom-module', {
  basedir: __dirname,
  readFileSync: (file) => {
    console.log('Reading:', file);
    return fs.readFileSync(file);
  },
  isFile: (file) => {
    try {
      const stat = fs.statSync(file);
      return stat.isFile();
    } catch {
      return false;
    }
  }
});

Package Processing Options

Transform package.json contents and handle custom package processing logic synchronously.

interface SyncPackageOptions {
  /** Custom sync package.json reading function */
  readPackageSync?: ReadPackageSyncFunction;
  /** Transform package.json contents before looking at main field */
  packageFilter?: (pkg: object, dir: string) => object;
  /** Transform paths within packages */
  pathFilter?: (pkg: object, path: string, relativePath: string) => string;
  /** Custom package candidate path iterator */
  packageIterator?: PackageIteratorFunction;
}

/**
 * Custom sync package.json reading function
 */
interface ReadPackageSyncFunction {
  (readFileSync: Function, pkgfile: string): object | undefined;
}

/**
 * Custom package candidate path iterator
 */
interface PackageIteratorFunction {
  (request: string, start: string, getPackageCandidates: () => string[], opts: SyncResolveOptions): string[];
}

Usage Example:

const resolve = require('resolve');

const res = resolve.sync('my-package', {
  basedir: __dirname,
  packageFilter: (pkg, dir) => {
    // Note: In sync version, second parameter is dir, not pkgfile
    // This will change to pkgfile in v2
    if (pkg.name === 'my-package') {
      pkg.main = 'dist/index.js';
    }
    return pkg;
  },
  pathFilter: (pkg, path, relativePath) => {
    if (pkg.name === 'my-package' && path.endsWith('.js')) {
      return path.replace('.js', '.min.js');
    }
    return path;
  }
});

Path Resolution Options

Control module search paths and path resolution behavior.

interface SyncPathOptions {
  /** Custom require.paths array or function for path resolution */
  paths?: string[] | PathsFunction;
}

/**
 * Function for custom path resolution logic
 */
interface PathsFunction {
  (request: string, start: string, getNodeModulesDirs: () => string[], opts: SyncResolveOptions): string[];
}

Usage Example:

const resolve = require('resolve');

const res = resolve.sync('custom-lib', {
  basedir: __dirname,
  paths: (request, start, getNodeModulesDirs, opts) => {
    const standardPaths = getNodeModulesDirs();
    return ['/custom/modules', ...standardPaths];
  }
});

Error Handling

Error Types

All sync resolution errors are thrown synchronously instead of being passed to callbacks.

interface ResolveError extends Error {
  /** Error code indicating the type of resolution failure */
  code: 'MODULE_NOT_FOUND' | 'INVALID_PACKAGE_MAIN';
  /** Original error message */
  message: string;
}

Error Scenarios

MODULE_NOT_FOUND: The specified module path could not be resolved.

const resolve = require('resolve');

try {
  resolve.sync('nonexistent-module', { basedir: __dirname });
} catch (err) {
  if (err.code === 'MODULE_NOT_FOUND') {
    console.error('Module not found:', err.message);
    // "Cannot find module 'nonexistent-module' from '/current/directory'"
  }
}

INVALID_PACKAGE_MAIN: A package.json was encountered with an invalid main property.

try {
  resolve.sync('broken-package', { basedir: __dirname });
} catch (err) {
  if (err.code === 'INVALID_PACKAGE_MAIN') {
    console.error('Invalid package main:', err.message);
    // 'package "broken-package" `main` must be a string'
  }
}

Default Options

The sync resolver uses the following default options when not specified:

const defaultOptions = {
  paths: [],
  basedir: __dirname, // Directory of calling file
  extensions: ['.js'],
  includeCoreModules: true,
  readFileSync: fs.readFileSync,
  isFile: function(file) {
    try {
      const stat = fs.statSync(file, { throwIfNoEntry: false });
      return !!stat && (stat.isFile() || stat.isFIFO());
    } catch (e) {
      if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false;
      throw e;
    }
  },
  isDirectory: function(dir) {
    try {
      const stat = fs.statSync(dir, { throwIfNoEntry: false });
      return !!stat && stat.isDirectory();
    } catch (e) {
      if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false;
      throw e;
    }
  },
  realpathSync: function(file) {
    try {
      const realpath = typeof fs.realpathSync.native === 'function' 
        ? fs.realpathSync.native 
        : fs.realpathSync;
      return realpath(file);
    } catch (realPathErr) {
      if (realPathErr.code !== 'ENOENT') throw realPathErr;
    }
    return file;
  },
  readPackageSync: function(readFileSync, pkgfile) {
    const body = readFileSync(pkgfile);
    try {
      return JSON.parse(body);
    } catch (jsonErr) {
      // Return undefined for invalid JSON
    }
  },
  moduleDirectory: 'node_modules',
  preserveSymlinks: true
};

Install with Tessl CLI

npx tessl i tessl/npm-resolve

docs

async-resolution.md

cli.md

core-modules.md

index.md

sync-resolution.md

tile.json