defmodule ExOutlines.MixProject do use Mix.Project @version "0.2.0" @source_url "https://github.com/thanos/ex_outlines" def project do [ app: :ex_outlines, version: @version, elixir: "~> 1.15", start_permanent: Mix.env() == :prod, consolidate_protocols: Mix.env() != :test, deps: deps(), package: package(), description: description(), name: "ExOutlines", source_url: @source_url, docs: docs(), test_coverage: [tool: ExCoveralls], preferred_cli_env: [ coveralls: :test, "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test, "coveralls.github": :test ], dialyzer: [ plt_add_apps: [:ex_unit], plt_file: {:no_warn, "priv/plts/dialyzer.plt"}, flags: [:error_handling, :underspecs] ], aliases: [ setup: ["deps.get"], lint: ["format --check-formatted", "credo --strict", "dialyzer"], precommit: ["compile --warnings-as-errors", "deps.unlock --unused", "format", "test"], verify: &verify/1 ] ] end def application do [ extra_applications: [:logger, :inets, :ssl, :public_key] ] end defp deps do [ {:jason, "~> 1.4"}, {:telemetry, "~> 1.2"}, {:ecto, "~> 3.11", optional: true}, {:benchee, "~> 1.3", only: :dev}, {:benchee_html, "~> 1.0", only: :dev}, {:ex_doc, "~> 0.31", only: :dev, runtime: false}, {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, {:excoveralls, "~> 0.18", only: :test}, {:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false} ] end defp description do """ Deterministic structured output from LLMs via retry-repair loops. Backend-agnostic constraint satisfaction for Elixir. """ end defp package do [ licenses: ["MIT"], links: %{ "GitHub" => @source_url, "Changelog" => "#{@source_url}/blob/main/CHANGELOG.md" }, maintainers: ["Thanos Vassilakis"], files: ~w(lib .formatter.exs mix.exs README.md LICENSE CHANGELOG.md) ] end defp docs do [ main: "ExOutlines", source_ref: "v#{@version}", source_url: @source_url, extras: extras(), groups_for_extras: groups_for_extras(), groups_for_modules: groups_for_modules() ] end defp extras do [ # Root documentation "README.md": [title: "Overview"], "CHANGELOG.md": [title: "Changelog"], LICENSE: [title: "License"], # Getting started guides "guides/getting_started.md": [title: "Getting Started"], "guides/core_concepts.md": [title: "Core Concepts"], # Core guides "guides/schema_patterns.md": [title: "Schema Patterns"], "guides/architecture.md": [title: "Architecture"], "guides/batch_processing.md": [title: "Batch Processing"], # Integration guides "guides/phoenix_integration.md": [title: "Phoenix Integration"], "guides/ecto_schema_adapter.md": [title: "Ecto Schema Adapter"], # Best practices "guides/testing_strategies.md": [title: "Testing Strategies"], "guides/error_handling.md": [title: "Error Handling"], # Livebook tutorials - Beginner "livebooks/getting_started.livemd": [title: "Livebook: Getting Started"], # Livebook tutorials - Intermediate "livebooks/named_entity_extraction.livemd": [title: "Livebook: Named Entity Extraction"], "livebooks/dating_profiles.livemd": [title: "Livebook: Dating Profiles"], "livebooks/qa_with_citations.livemd": [title: "Livebook: Q&A with Citations"], "livebooks/sampling_and_self_consistency.livemd": [ title: "Livebook: Sampling & Self-Consistency" ], # Livebook tutorials - Advanced "livebooks/models_playing_chess.livemd": [title: "Livebook: Models Playing Chess"], "livebooks/simtom_theory_of_mind.livemd": [title: "Livebook: SimToM Theory of Mind"], "livebooks/chain_of_thought.livemd": [title: "Livebook: Chain of Thought"], "livebooks/react_agent.livemd": [title: "Livebook: ReAct Agent"], "livebooks/structured_generation_workflow.livemd": [title: "Livebook: Structured Generation"], # Livebook tutorials - Vision & Documents "livebooks/read_pdfs.livemd": [title: "Livebook: PDF Reading"], "livebooks/earnings_reports.livemd": [title: "Livebook: Earnings Reports"], "livebooks/receipt_digitization.livemd": [title: "Livebook: Receipt Digitization"], "livebooks/extract_event_details.livemd": [title: "Livebook: Extract Event Details"], # Livebooks README "livebooks/README.md": [title: "Livebook Tutorials Index"], # Reference "DOCUMENTATION_INDEX.md": [title: "Documentation Index"], "GAP_ANALYSIS.md": [title: "Gap Analysis vs Python Outlines"] # "GITHUB_ANALYSIS_SUMMARY.md": [title: "GitHub Analysis Summary"] ] end defp groups_for_extras do [ "Getting Started": ~r/guides\/(getting_started|core_concepts)/, "Core Guides": ~r/guides\/(schema_patterns|architecture|batch_processing)/, Integration: ~r/guides\/(phoenix_integration|ecto_schema_adapter)/, "Best Practices": ~r/guides\/(testing_strategies|error_handling)/, "Livebook Tutorials": ~r/livebooks\//, Reference: ~r/(DOCUMENTATION_INDEX|GAP_ANALYSIS|GITHUB_ANALYSIS_SUMMARY)/, "Project Info": ~r/(README|CHANGELOG|LICENSE)/ ] end defp groups_for_modules do [ "Core API": [ ExOutlines, ExOutlines.Spec, ExOutlines.Spec.Schema ], Backends: [ ExOutlines.Backend, ExOutlines.Backend.HTTP, ExOutlines.Backend.Anthropic, ExOutlines.Backend.Mock ], "Error Handling": [ ExOutlines.Diagnostics ], "Ecto Integration": [ ExOutlines.Ecto.SchemaAdapter ] ] end defp verify(_) do steps = [ {"compile --warnings-as-errors", :dev}, {"format --check-formatted", :dev}, {"credo --strict", :dev}, # {"sobelow --config", :dev}, {"dialyzer", :dev}, {"test --cover", :test}, {"docs --warnings-as-errors", :dev} ] Enum.each(steps, fn {task, env} -> Mix.shell().info(IO.ANSI.format([:bright, "==> mix #{task}", :reset])) mix_executable = System.find_executable("mix") || Mix.raise("Could not find `mix` executable on PATH") {_, exit_code} = System.cmd(mix_executable, String.split(task), env: [{"MIX_ENV", to_string(env)}], into: IO.stream(:stdio, :line), stderr_to_stdout: true ) if exit_code != 0 do Mix.raise("mix #{task} failed (exit code #{exit_code})") end end) Mix.shell().info(IO.ANSI.format([:green, :bright, "\nAll verification checks passed!", :reset])) end end