All files / core/src/utils dependency-utils.js

0% Statements 0/38
0% Branches 0/14
0% Functions 0/10
0% Lines 0/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127                                                                                                                                                                                                                                                             
/**
 * Utility functions for handling optional peer dependencies
 */
 
/**
 * Check if a peer dependency is available
 * @param {string} packageName - Name of the package to check
 * @returns {boolean} - Whether the package is available
 */
export function isPeerDependencyAvailable(packageName) {
  try {
    // Try to import the package synchronously using require.resolve
    // This is more compatible with code analysis tools
    if (typeof require !== 'undefined' && require.resolve) {
      require.resolve(packageName);
      return true;
    }
    // Fallback: assume available if require is not available (browser context)
    return false;
  } catch {
    return false;
  }
}
 
/**
 * Dynamically import a peer dependency with _error handling
 * @param {string} packageName - Name of the package to import
 * @param {string} integrationName - Human-readable name of the integration
 * @returns {Promise<any>} - The imported module
 * @throws {Error} - If the dependency is not available
 */
export async function importPeerDependency(packageName, integrationName) {
  try {
    return await import(packageName);
  } catch {
    throw new Error(
      `${integrationName} integration requires the '${packageName}' package to be installed.\n` +
      `Please install it with: npm install ${packageName}\n` +
      `Or with pnpm: pnpm add ${packageName}\n` +
      `Or with yarn: yarn add ${packageName}`
    );
  }
}
 
/**
 * Create a lazy-loaded integration that only imports dependencies when needed
 * @param {string} packageName - Name of the package to import
 * @param {string} integrationName - Human-readable name of the integration
 * @param {Function} createIntegration - Function that creates the integration using the imported package
 * @returns {Function} - Lazy-loaded integration function
 */
export function createLazyIntegration(packageName, integrationName, createIntegration) {
  let cachedIntegration = null;
  let importPromise = null;
 
  return async function(...args) {
    // Return cached integration if available
    if (cachedIntegration) {
      return cachedIntegration(...args);
    }
 
    // Avoid multiple concurrent imports
    if (!importPromise) {
      importPromise = importPeerDependency(packageName, integrationName)
        .then(module => {
          cachedIntegration = createIntegration(module);
          return cachedIntegration;
        });
    }
 
    const integration = await importPromise;
    return integration(...args);
  };
}
 
/**
 * Check multiple peer dependencies and provide helpful _error messages
 * @param {Array<{package: string, integration: string}>} dependencies - List of dependencies to check
 * @returns {Object} - Object with availability status for each dependency
 */
export function checkPeerDependencies(dependencies) {
  const results = {};
  const missing = [];
 
  for (const { package: packageName, integration } of dependencies) {
    const available = isPeerDependencyAvailable(packageName);
    results[packageName] = available;
    
    if (!available) {
      missing.push({ package: packageName, integration });
    }
  }
 
  if (missing.length > 0) {
    const installCommands = missing.map(({ package: pkg }) => pkg).join(' ');
    const integrationsList = missing.map(({ integration }) => integration).join(', ');
    
    console.warn(
      `Optional dependencies missing for ${integrationsList} integration(s).\n` +
      `To use these integrations, install: npm install ${installCommands}\n` +
      `Or with pnpm: pnpm add ${installCommands}\n` +
      `Or with yarn: yarn add ${installCommands}`
    );
  }
 
  return results;
}
 
/**
 * Create a function that checks for a dependency before executing
 * @param {string} packageName - Name of the package required
 * @param {string} integrationName - Human-readable name of the integration
 * @param {Function} fn - Function to execute if dependency is available
 * @returns {Function} - Wrapped function with dependency check
 */
export function requirePeerDependency(packageName, integrationName, fn) {
  return function(...args) {
    if (!isPeerDependencyAvailable(packageName)) {
      throw new Error(
        `${integrationName} integration requires the '${packageName}' package to be installed.\n` +
        `Please install it with: npm install ${packageName}`
      );
    }
    return fn.apply(this, args);
  };
}