Skip to main content

lib/npm/registry/url.ex

defmodule NPM.Registry.URL do
  @moduledoc """
  Constructs registry API URLs for package operations.
  """

  @default_registry "https://registry.npmjs.org"

  @doc """
  Returns the package metadata URL.
  """
  @spec package_url(String.t(), String.t()) :: String.t()
  def package_url(name, registry \\ @default_registry) do
    "#{normalize(registry)}/#{encode_name(name)}"
  end

  @doc """
  Returns the URL for a specific version.
  """
  @spec version_url(String.t(), String.t(), String.t()) :: String.t()
  def version_url(name, version, registry \\ @default_registry) do
    "#{package_url(name, registry)}/#{version}"
  end

  @doc """
  Returns the tarball URL.
  """
  @spec tarball_url(String.t(), String.t(), String.t()) :: String.t()
  def tarball_url(name, version, registry \\ @default_registry) do
    base = normalize(registry)
    basename = Path.basename(name)
    "#{base}/#{encode_name(name)}/-/#{basename}-#{version}.tgz"
  end

  @doc """
  Returns the search API URL.
  """
  @spec search_url(String.t(), keyword()) :: String.t()
  def search_url(query, opts \\ []) do
    registry = Keyword.get(opts, :registry, @default_registry)
    size = Keyword.get(opts, :size, 20)
    "#{normalize(registry)}/-/v1/search?text=#{URI.encode(query)}&size=#{size}"
  end

  @doc """
  Returns the abbreviated (corgi) metadata URL.
  """
  @spec abbreviated_url(String.t(), String.t()) :: String.t()
  def abbreviated_url(name, registry \\ @default_registry) do
    package_url(name, registry)
  end

  @doc """
  Checks if a URL points to the default npm registry.
  """
  @spec default_registry?(String.t()) :: boolean()
  def default_registry?(url) do
    normalized = normalize(url)
    normalized == @default_registry or normalized == "https://registry.npmmirror.com"
  end

  @doc """
  Returns the default registry URL.
  """
  @spec default_registry :: String.t()
  def default_registry, do: @default_registry

  defp normalize(url), do: String.trim_trailing(url, "/")

  defp encode_name(name) do
    if NPM.Scope.scoped?(name) do
      name |> String.replace("/", "%2f")
    else
      name
    end
  end
end