defmodule NPM.ErrorMessage do @moduledoc """ Structured error formatting for npm operations. Provides consistent, helpful error messages with suggestions for resolution. """ @doc """ Formats an error tuple into a user-friendly message. """ @spec format({:error, atom()} | {:error, atom(), term()}) :: String.t() def format({:error, :no_package_json}) do "package.json not found.\nRun `mix npm.init` to create one." end def format({:error, :no_lockfile}) do "package-lock.json not found.\nRun `mix npm.install` to generate a lockfile." end def format({:error, :frozen_lockfile}) do "package-lock.json is out of sync with package.json.\nRun `mix npm.install` to update the lockfile." end def format({:error, :resolution_failed}) do "Dependency resolution failed.\nCheck for conflicting version ranges in package.json." end def format({:error, :integrity_mismatch, name}) do "Integrity check failed for #{name}.\nTry clearing the cache: `mix npm.cache clean`" end def format({:error, :network_error}) do "Network error. Check your internet connection and registry URL." end def format({:error, :package_not_found, name}) do "Package '#{name}' not found in the registry.\nCheck the package name for typos." end def format({:error, reason}) when is_atom(reason) do "Error: #{reason}" end def format({:error, reason}) do "Error: #{inspect(reason)}" end @doc """ Returns a suggestion for a given error. """ @spec suggestion(atom()) :: String.t() | nil def suggestion(:no_package_json), do: "mix npm.init" def suggestion(:no_lockfile), do: "mix npm.install" def suggestion(:frozen_lockfile), do: "mix npm.install" def suggestion(:resolution_failed), do: "Check package.json for conflicts" def suggestion(:integrity_mismatch), do: "mix npm.cache clean" def suggestion(:network_error), do: "Check connectivity and .npmrc registry" def suggestion(_), do: nil @doc """ Checks if an error is retryable. """ @spec retryable?(atom()) :: boolean() def retryable?(:network_error), do: true def retryable?(:timeout), do: true def retryable?(:registry_unavailable), do: true def retryable?(_), do: false end