defmodule NPM.ProjectInit do @moduledoc """ Initializes an Elixir project for npm dependency management. Creates package.json, .gitignore entries, and verifies configuration. """ @doc """ Checks if a project is already initialized for npm. """ @spec initialized?(String.t()) :: boolean() def initialized?(dir \\ ".") do File.exists?(Path.join(dir, "package.json")) end @doc """ Creates a package.json from project metadata. """ @spec create_package_json(String.t(), keyword()) :: :ok | {:error, term()} def create_package_json(dir \\ ".", opts \\ []) do path = Path.join(dir, "package.json") if File.exists?(path) and not Keyword.get(opts, :force, false) do {:error, :already_exists} else content = build_package_json(opts) File.write(path, :json.encode(content)) end end @doc """ Returns a checklist of items to verify for npm setup. """ @spec checklist(String.t()) :: [%{item: String.t(), ok: boolean()}] def checklist(dir \\ ".") do [ %{item: "package.json exists", ok: File.exists?(Path.join(dir, "package.json"))}, %{item: ".gitignore covers node_modules", ok: gitignore_ok?(dir)}, %{item: "mix.exs has npm compiler", ok: has_compiler?(dir)} ] end @doc """ Returns true if all checklist items pass. """ @spec ready?(String.t()) :: boolean() def ready?(dir \\ ".") do checklist(dir) |> Enum.all?(& &1.ok) end @doc """ Formats the checklist for display. """ @spec format_checklist([map()]) :: String.t() def format_checklist(items) do Enum.map_join(items, "\n", fn item -> mark = if item.ok, do: "✓", else: "✗" " #{mark} #{item.item}" end) end defp build_package_json(opts) do %{ "name" => Keyword.get(opts, :name, "elixir-app"), "version" => Keyword.get(opts, :version, "0.1.0"), "private" => true, "dependencies" => %{}, "devDependencies" => %{} } end defp gitignore_ok?(dir) do path = Path.join(dir, ".gitignore") case File.read(path) do {:ok, content} -> NPM.Gitignore.covers_node_modules?(content) _ -> false end end defp has_compiler?(dir) do path = Path.join(dir, "mix.exs") case File.read(path) do {:ok, content} -> String.contains?(content, ":npm") _ -> false end end end