defmodule NumberF.MixProject do use Mix.Project @version "0.3.0" @github_url "https://github.com/jamesnjovu/elixir_number_functions" @docs_url "https://hexdocs.pm/number_f" def project do [ app: :number_f, version: @version, elixir: "~> 1.14", start_permanent: Mix.env() == :prod, elixirc_paths: elixirc_paths(Mix.env()), deps: deps(), aliases: aliases(), name: "NumberF", description: description(), package: package(), docs: docs(), source_url: @github_url, homepage_url: @docs_url, xref: [exclude: [:httpc, :public_key]], test_coverage: [tool: ExCoveralls], # Ratcheted deliberately: the real figure today is ~76%. Raise this as each # phase adds tests, so coverage can never silently regress. preferred_cli_env: [ coveralls: :test, "coveralls.detail": :test, "coveralls.html": :test, "coveralls.github": :test ], dialyzer: [ plt_add_apps: [:mix, :ex_unit], # Per-env PLT: the dev and test dependency sets differ, and one shared file # goes stale the moment the environment changes. plt_file: {:no_warn, "priv/plts/dialyzer-#{Mix.env()}.plt"} ] ] end # A pure computation library needs no supervision tree. There is deliberately no # `mod:` key: NumberF.Application was an empty supervisor whose only effect was to # make `Supervisor.start_link/2` return {:error, {:already_started, _}} in tests. def application do [extra_applications: [:logger]] end # test/support holds shared test helpers; consumers always build in :prod. defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"] defp deps do [ # The only runtime dependency, and deliberately so — "one zero-config # dependency" is a stated selling point. `~> 3.0` is allowed so consumers can # take the fix for GHSA-rhv4-8758-jx7v (unbounded exponent DoS, decimal < 3.0.0). # Only new/to_float/from_float/to_string/round/add are used, all stable across # both majors; the full suite is verified green against 2.3.0 and 3.1.1. # Note this needs jason >= 1.4.5 in the dev/test closure — 1.4.4 declared # `decimal ~> 1.0 or ~> 2.0` and held the whole resolution below 3. {:decimal, "~> 2.0 or ~> 3.0"}, # Tooling. :test as well as :dev for credo/dialyxir — the CI lint job runs with # MIX_ENV=test, where a dev-only dep makes `mix credo` an unknown task. {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, {:excoveralls, "~> 0.18", only: :test, runtime: false}, {:ex_doc, "~> 0.40", only: :dev, runtime: false}, {:mix_audit, "~> 2.0", only: [:dev, :test], runtime: false} ] end defp aliases do [ # One command for everything CI's lint job gates on, so a local run and a CI # run cannot disagree about whether the tree is clean. lint: [ "format --check-formatted", "compile --warnings-as-errors", "credo --strict" ] ] end # Shown on hex.pm and indexed by Hex search, Google, and LLM crawlers. # Lead with the concrete nouns people actually search for. defp description do """ Number formatting, currency and financial math for Elixir. Format currency and \ numbers for 22 locales, convert numbers to words and Roman numerals, calculate \ compound interest, EMI, VAT and income tax, run statistics, validate credit \ cards, and convert units. One zero-config dependency.\ """ end defp package do [ name: "number_f", files: ~w(lib guides priv/static/images .formatter.exs mix.exs README.md LICENSE CHANGELOG.md CONTRIBUTING.md llms.txt), # `mix test.numberf_*` are for developing this library, not for consumers. exclude_patterns: ["lib/mix"], licenses: ["MIT"], links: %{ "GitHub" => @github_url, "Documentation" => @docs_url, "Changelog" => "#{@github_url}/blob/master/CHANGELOG.md", "Cheatsheet" => "#{@docs_url}/cheatsheet.html", "llms.txt" => "#{@docs_url}/llms.txt", "Issues" => "#{@github_url}/issues" }, maintainers: ["James Njovu"] ] end defp docs do [ main: "readme", logo: "priv/static/images/logo.svg", favicon: "priv/static/images/favicon.svg", canonical: @docs_url, language: "en", api_reference: true, filter_modules: fn module, _ -> not match?("Elixir.Mix.Tasks." <> _, Atom.to_string(module)) end, # "markdown" is what emits llms.txt / llms-full.txt for AI assistants. formatters: ["html", "markdown"], source_ref: "v#{@version}", source_url_pattern: "#{@github_url}/blob/v#{@version}/%{path}#L%{line}", authors: ["James Njovu"], assets: %{"priv/static/images" => "assets"}, before_closing_head_tag: &before_closing_head_tag/1, extras: [ "README.md": [title: "Overview"], "guides/getting-started.md": [title: "Getting Started"], "guides/cheatsheet.cheatmd": [title: "Cheatsheet"], "guides/currency-formatting.md": [title: "Currency Formatting"], "guides/financial-calculations.md": [title: "Financial Calculations"], "guides/internationalization.md": [title: "Internationalization"], "guides/faq.md": [title: "FAQ"], "CHANGELOG.md": [title: "Changelog"], "CONTRIBUTING.md": [title: "Contributing"] ], groups_for_extras: [ Guides: [ "guides/getting-started.md", "guides/cheatsheet.cheatmd", "guides/currency-formatting.md", "guides/financial-calculations.md", "guides/internationalization.md", "guides/faq.md" ], Other: ["CHANGELOG.md", "CONTRIBUTING.md"] ], # Generated from the `@doc group:` metadata on each delegation, so the sidebar # cannot drift from the code. With 261 function arities on one module, an # ungrouped page is a wall of names for a reader and one undifferentiated # chunk for anything indexing it. groups_for_docs: [ Formatting: &(&1[:group] == "Formatting"), Currency: &(&1[:group] == "Currency"), Text: &(&1[:group] == "Text"), Financial: &(&1[:group] == "Financial"), Tax: &(&1[:group] == "Tax"), Statistics: &(&1[:group] == "Statistics"), Precision: &(&1[:group] == "Precision"), Validation: &(&1[:group] == "Validation"), Math: &(&1[:group] == "Math"), Units: &(&1[:group] == "Units"), Dates: &(&1[:group] == "Dates"), Humanize: &(&1[:group] == "Humanize"), Internationalization: &(&1[:group] == "Internationalization"), Introspection: &(&1[:group] == "Introspection") ], groups_for_modules: [ "Core Functions": [ NumberF, NumberF.Registry ], "Calculation Modules": [ NumberF.Calculations, NumberF.Financial, NumberF.Statistics, NumberF.Precision, NumberF.Tax ], "Formatting Modules": [ NumberF.Formatter, NumberF.CustomFormatter, NumberF.Currencies ], "Conversion Modules": [ NumberF.Metrics ], "Validation & Utilities": [ NumberF.Validation ], "Date Handling": [ NumberF.DateCalculations ], Internationalization: [ NumberF.I18n ] ], nest_modules_by_prefix: [ NumberF ], skip_undefined_reference_warnings_on: [ "CHANGELOG.md" ], # Internal modules deliberately named in the docs as "not public API". skip_code_autolink_to: [ "NumberF.Currency", "NumberF.Memory", "NumberF.Randomizer", "NumberF.Helper", "NumberF.NumbersToWords", "NumberF.NumberToWord" ] ] end # Static metadata in . Emitted server-side so crawlers and LLM # fetchers that do not execute JavaScript still see it. defp before_closing_head_tag(:html) do """ """ end defp before_closing_head_tag(_), do: "" end