Current section
Files
Jump to
Current section
Files
lib/exfmt.ex
defmodule Exfmt do
@moduledoc """
Exfmt, an opinionated Elixir source code formatter. 🌸
aka The everyone's favourite Elixir-to-Elixir compiler.
## API
Functions in this module can be considered part of Exfmt's
public interface, and can be presumed stable. Functions exposed
by other modules may change at any time without warning,
especially before v1.0.0.
"""
alias Exfmt.{Ast, Algebra, Comment, Context, SyntaxError}
@max_width 80
@doc ~S"""
Format a string of Elixir source code.
iex> format("[1,2,3]")
{:ok, "[1, 2, 3]\n"}
"""
@spec format(String.t, integer) :: {:ok, String.t} | SyntaxError.t
def format(source, max_width \\ @max_width) do
with {:ok, tree} <- Code.string_to_quoted(source),
{:ok, comments} <- Comment.extract_comments(source) do
{:ok, do_format(tree, comments, max_width)}
else
{:error, error} ->
SyntaxError.exception(error)
end
end
@doc ~S"""
Format a string of Elixir source code, throwing an exception
in the event of failure.
iex> format!("[1,2,3]")
"[1, 2, 3]\n"
"""
@spec format!(String.t, integer) :: String.t
def format!(source, max_width \\ @max_width) do
case format(source, max_width) do
%SyntaxError{} = error ->
raise error
{:ok, formatted} ->
formatted
end
end
@doc """
Check that a string of source code conforms to the exfmt style.
If formatting the source code would not result in the source code
changing this function will return `:ok`.
"""
@spec check(String.t, integer) :: :ok | {:format_error, String.t} | SyntaxError.t
def check(source, max_width \\ @max_width) do
with {:ok, formatted} <- format(source, max_width) do
if source == formatted do
:ok
else
{:format_error, formatted}
end
end
end
#
# Private
#
defp do_format(tree, comments, max_width) do
comments
|> Comment.merge(tree)
|> Ast.to_algebra(Context.new)
|> Algebra.format(max_width)
|> IO.chardata_to_string()
|> (& &1 <> "\n").()
end
end