defmodule NPM.Corepack do @moduledoc """ Parses corepack/packageManager field from package.json. The `packageManager` field specifies which package manager and version to use (e.g., `"npm@10.2.0"`, `"pnpm@8.10.0"`). """ @doc """ Extracts the packageManager field. """ @spec get(map()) :: String.t() | nil def get(%{"packageManager" => pm}) when is_binary(pm), do: pm def get(_), do: nil @doc """ Parses the package manager name from the field. """ @spec manager_name(map()) :: String.t() | nil def manager_name(data) do case get(data) do nil -> nil pm -> pm |> String.split("@", parts: 2) |> hd() end end @doc """ Parses the package manager version. """ @spec manager_version(map()) :: String.t() | nil def manager_version(data) do case get(data) do nil -> nil pm -> case String.split(pm, "@", parts: 2) do [_, version] -> strip_hash(version) _ -> nil end end end @doc """ Checks if the project uses npm. """ @spec npm?(map()) :: boolean() def npm?(data), do: manager_name(data) == "npm" @doc """ Checks if the project uses pnpm. """ @spec pnpm?(map()) :: boolean() def pnpm?(data), do: manager_name(data) == "pnpm" @doc """ Checks if the project uses yarn. """ @spec yarn?(map()) :: boolean() def yarn?(data), do: manager_name(data) == "yarn" @doc """ Checks if corepack is configured. """ @spec configured?(map()) :: boolean() def configured?(data), do: get(data) != nil @doc """ Formats for display. """ @spec format(map()) :: String.t() def format(data) do case get(data) do nil -> "No package manager configured" pm -> "Package manager: #{pm}" end end defp strip_hash(version) do case String.split(version, "+", parts: 2) do [ver | _] -> ver _ -> version end end end