CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-node-gyp

Node.js native addon build tool

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

utilities.mddocs/

Utility Functions

Utility functions provide core infrastructure for file operations, network requests, system registry access, and cross-platform process execution used throughout node-gyp.

Capabilities

HTTP Download Utilities

Handles HTTP/HTTPS downloads with proper headers, proxy support, and CA certificate handling.

/**
 * Downloads files with proxy support and proper headers
 * @param {Gyp} gyp - The gyp instance for configuration
 * @param {string} url - URL to download from
 * @returns {Promise<Response>} Fetch response object
 */
async function download(gyp: Gyp, url: string): Promise<Response>;

/**
 * Reads CA certificate file for HTTPS downloads
 * @param {string} filename - Path to CA certificate file
 * @returns {Promise<string>} CA certificate content
 */
async function readCAFile(filename: string): Promise<string>;

Usage Examples:

const { download, readCAFile } = require('node-gyp/lib/download');
const gyp = require('node-gyp');

// Download with gyp configuration
const gypInstance = gyp();
gypInstance.opts.proxy = 'http://proxy.company.com:8080';

try {
  const response = await download(gypInstance, 'https://nodejs.org/dist/v16.14.0/node-v16.14.0-headers.tar.gz');
  const buffer = await response.buffer();
  console.log('Downloaded', buffer.length, 'bytes');
} catch (error) {
  console.error('Download failed:', error.message);
}

// Use custom CA certificate
try {
  const caCert = await readCAFile('/path/to/ca-certificates.crt');
  console.log('Loaded CA certificate');
} catch (error) {
  console.error('Failed to read CA file:', error.message);
}

Download Features:

  • Proxy Support: Honors proxy and noproxy configuration
  • Custom CA: Supports custom CA certificate files
  • User Agent: Sets appropriate User-Agent headers
  • Timeout Handling: Configurable request timeouts
  • Error Handling: Detailed error reporting for network issues

Process Execution Utilities

Cross-platform utilities for executing external processes with proper error handling.

/**
 * Promise wrapper for child_process.execFile with proper error handling
 * @param {...any} args - Arguments passed to execFile (command, args, options, callback)
 * @returns {Promise<[Error?, string?, string?]>} Tuple of [error, stdout, stderr]
 */
async function execFile(...args: any[]): Promise<[Error?, string?, string?]>;

Usage Examples:

const { execFile } = require('node-gyp/lib/util');

// Execute command and handle results
const [error, stdout, stderr] = await execFile('python', ['--version']);

if (error) {
  console.error('Command failed:', error.message);
} else {
  console.log('Python version:', stdout.trim());
}

// Execute with options
const [error, stdout, stderr] = await execFile('make', ['-j4'], {
  cwd: './build',
  encoding: 'utf8',
  timeout: 30000
});

if (!error) {
  console.log('Build completed successfully');
}

Windows Registry Utilities

Windows-specific utilities for reading registry values, used for toolchain discovery.

/**
 * Gets a value from the Windows registry
 * @param {string} key - Registry key path
 * @param {string} value - Value name to read
 * @param {string[]} [addOpts] - Additional reg.exe options
 * @returns {Promise<string>} Registry value content
 */
async function regGetValue(key: string, value: string, addOpts?: string[]): Promise<string>;

/**
 * Searches multiple registry keys for a value, returning the first match
 * @param {string[]} keys - Array of registry key paths to search
 * @param {string} value - Value name to find
 * @param {string[]} [addOpts] - Additional reg.exe options
 * @returns {Promise<string>} First matching registry value
 */
async function regSearchKeys(keys: string[], value: string, addOpts?: string[]): Promise<string>;

Usage Examples:

const { regGetValue, regSearchKeys } = require('node-gyp/lib/util');

// Windows only - get specific registry value
if (process.platform === 'win32') {
  try {
    const vsPath = await regGetValue(
      'HKLM\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\Setup\\VS',
      'ProductDir'
    );
    console.log('Visual Studio 2015 path:', vsPath);
  } catch (error) {
    console.log('Visual Studio 2015 not found');
  }

  // Search multiple keys for Visual Studio installations
  const vsKeys = [
    'HKLM\\SOFTWARE\\Microsoft\\VisualStudio\\16.0\\Setup\\VS',
    'HKLM\\SOFTWARE\\Microsoft\\VisualStudio\\15.0\\Setup\\VS',
    'HKLM\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\Setup\\VS'
  ];

  try {
    const vsPath = await regSearchKeys(vsKeys, 'ProductDir');
    console.log('Found Visual Studio at:', vsPath);
  } catch (error) {
    console.log('No Visual Studio installations found');
  }
}

File Access Utilities

Cross-platform file access validation utilities.

/**
 * Returns the first file or directory from candidates that is readable by current user
 * @param {string} logprefix - Prefix for log messages
 * @param {string} dir - Base directory to search in
 * @param {string[]} candidates - Array of candidate file/directory names
 * @returns {string | undefined} Path to first accessible candidate or undefined
 */
function findAccessibleSync(logprefix: string, dir: string, candidates: string[]): string | undefined;

Usage Examples:

const { findAccessibleSync } = require('node-gyp/lib/util');

// Find first accessible Python executable
const pythonDir = '/usr/bin';
const pythonCandidates = ['python3.9', 'python3.8', 'python3', 'python'];

const pythonPath = findAccessibleSync('python', pythonDir, pythonCandidates);
if (pythonPath) {
  console.log('Found Python at:', pythonPath);
} else {
  console.log('No accessible Python found');
}

// Find Node.js headers
const nodeDir = '/usr/local/include';
const headerCandidates = ['node/node.h', 'nodejs/node.h'];

const headerPath = findAccessibleSync('headers', nodeDir, headerCandidates);
if (headerPath) {
  console.log('Found Node.js headers at:', headerPath);
}

Logging Integration

All utilities integrate with the node-gyp logging system:

const log = require('node-gyp/lib/log');
const { withPrefix } = log;

// Create prefixed logger for utility functions
const utilLog = withPrefix('util');

utilLog.verbose('Executing command:', 'python --version');
utilLog.silly('Registry query:', 'HKLM\\SOFTWARE\\...');

Error Handling Patterns

Network Error Handling

const { download } = require('node-gyp/lib/download');

try {
  const response = await download(gypInstance, url);
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }
} catch (error) {
  if (error.code === 'ENOTFOUND') {
    console.error('DNS resolution failed for:', url);
  } else if (error.code === 'ECONNREFUSED') {
    console.error('Connection refused, check proxy settings');
  } else if (error.code === 'CERT_UNTRUSTED') {
    console.error('SSL certificate error, check CA configuration');
  } else {
    console.error('Download failed:', error.message);
  }
}

Process Execution Error Handling

const { execFile } = require('node-gyp/lib/util');

const [error, stdout, stderr] = await execFile('python', ['--version']);

if (error) {
  if (error.code === 'ENOENT') {
    console.error('Python executable not found in PATH');
  } else if (error.code === 'EACCES') {
    console.error('Permission denied executing Python');
  } else if (error.signal) {
    console.error('Python process killed by signal:', error.signal);
  } else {
    console.error('Python execution failed:', error.message);
  }
}

Registry Access Error Handling

const { regGetValue } = require('node-gyp/lib/util');

if (process.platform === 'win32') {
  try {
    const value = await regGetValue(key, valueName);
  } catch (error) {
    if (error.message.includes('cannot find')) {
      console.log('Registry key not found');
    } else if (error.message.includes('Access is denied')) {
      console.error('Registry access denied - run as administrator?');
    } else {
      console.error('Registry error:', error.message);
    }
  }
}

Integration Examples

Custom Download with Progress

const { download } = require('node-gyp/lib/download');
const fs = require('fs');

async function downloadWithProgress(gyp, url, outputPath) {
  const response = await download(gyp, url);
  const total = parseInt(response.headers.get('content-length') || '0');
  let downloaded = 0;

  const fileStream = fs.createWriteStream(outputPath);
  
  response.body.on('data', (chunk) => {
    downloaded += chunk.length;
    const percent = total ? (downloaded / total * 100).toFixed(1) : '?';
    process.stdout.write(`\rDownloading: ${percent}%`);
  });

  await new Promise((resolve, reject) => {
    response.body.pipe(fileStream);
    response.body.on('end', resolve);
    response.body.on('error', reject);
  });

  console.log('\nDownload completed');
}

Toolchain Validation Utility

const { execFile, findAccessibleSync } = require('node-gyp/lib/util');

async function validateBuildTools() {
  const results = {
    python: false,
    make: false,
    compiler: false
  };

  // Check Python
  const [pythonError] = await execFile('python', ['--version']);
  results.python = !pythonError;

  // Check Make
  const [makeError] = await execFile('make', ['--version']);
  results.make = !makeError;

  // Check compiler
  const compilerCandidates = ['gcc', 'clang', 'cl.exe'];
  for (const compiler of compilerCandidates) {
    const [compilerError] = await execFile(compiler, ['--version']);
    if (!compilerError) {
      results.compiler = compiler;
      break;
    }
  }

  return results;
}

// Usage
const toolchainStatus = await validateBuildTools();
console.log('Toolchain status:', toolchainStatus);

Cross-Platform Path Resolution

const { findAccessibleSync } = require('node-gyp/lib/util');
const path = require('path');

function findExecutable(name, searchPaths = []) {
  const defaultPaths = process.env.PATH.split(path.delimiter);
  const allPaths = [...searchPaths, ...defaultPaths];
  
  const extensions = process.platform === 'win32' ? ['.exe', '.cmd', '.bat'] : [''];
  
  for (const searchPath of allPaths) {
    const candidates = extensions.map(ext => name + ext);
    const found = findAccessibleSync('executable', searchPath, candidates);
    if (found) {
      return found;
    }
  }
  
  return null;
}

// Usage
const pythonPath = findExecutable('python3', ['/usr/local/bin', '/opt/python/bin']);
console.log('Python found at:', pythonPath);

Logging Utilities

Advanced logging functions for creating custom loggers and direct output control.

/**
 * Creates log functions with predefined prefix
 * @param {string} prefix - Prefix for log messages
 * @returns {object} Object with logging functions for each level
 */
function withPrefix(prefix: string): object;

/**
 * Direct stdout output function (can be nullified in tests)
 * @param {...any} args - Arguments to output
 */
function stdout(...args: any[]): void;

/**
 * Direct access to the logger instance
 * @type {Logger}
 */
const logger: Logger;

Usage Examples:

const { withPrefix, stdout, logger } = require('node-gyp/lib/log');

// Create prefixed logger
const myLog = withPrefix('custom');
myLog.info('This is a custom prefixed message');
myLog.verbose('Detailed information');
myLog.error('Error with custom prefix');

// Direct stdout access
stdout('Direct console output without logging formatting');

// Direct logger access
logger.level = 'verbose';
console.log('Current log level:', logger.level.id);

Process Release Utilities

Functions for processing Node.js release information and generating download URLs.

/**
 * Processes Node.js release information for downloads and configuration
 * @param {string[]} argv - Command arguments
 * @param {Gyp} gyp - Gyp instance for configuration
 * @param {string} defaultVersion - Default Node.js version
 * @param {object} defaultRelease - Default release object
 * @returns {object} Release information with URLs and paths
 */
function processRelease(
  argv: string[], 
  gyp: Gyp, 
  defaultVersion: string, 
  defaultRelease: object
): object;

Usage Example:

const processRelease = require('node-gyp/lib/process-release');
const gyp = require('node-gyp');

const gypInstance = gyp();
const releaseInfo = processRelease(
  ['16.14.0'], 
  gypInstance, 
  process.version, 
  process.release
);

console.log('Download URLs:', {
  tarball: releaseInfo.tarballUrl,
  headers: releaseInfo.headersUrl,
  lib32: releaseInfo.libUrl32,
  lib64: releaseInfo.libUrl64
});

Command Usage Information

Each command module exports a usage string for help text generation.

// All command modules export both function and usage
const buildCommand = require('node-gyp/lib/build');
const cleanCommand = require('node-gyp/lib/clean');
// etc.

/**
 * Usage description for each command
 * @type {string}
 */
buildCommand.usage: string;
cleanCommand.usage: string;
configureCommand.usage: string;
installCommand.usage: string;
listCommand.usage: string;
rebuildCommand.usage: string;
removeCommand.usage: string;

Usage Example:

const buildCommand = require('node-gyp/lib/build');
const cleanCommand = require('node-gyp/lib/clean');

console.log('Build command:', buildCommand.usage);
// "Invokes `msbuild` (on Windows) or `make` (on other platforms) and builds the module"

console.log('Clean command:', cleanCommand.usage);
// "Removes any generated build files and the \"out\" dir"

// Generate help for all commands
const commands = ['build', 'clean', 'configure', 'install', 'list', 'rebuild', 'remove'];
commands.forEach(cmd => {
  const cmdModule = require(`node-gyp/lib/${cmd}`);
  console.log(`${cmd}: ${cmdModule.usage}`);
});

docs

build-commands.md

core-build-system.md

dev-file-management.md

index.md

platform-toolchain.md

utilities.md

tile.json