defmodule Vnu do @moduledoc "General purpose validation functions for HTML, CSS, and SVG documents." alias Vnu.{Error, Result, Validator} @doc ~S""" Validates the given HTML document. Returns `{:ok, %Vnu.Result{}}` if the validation process finished successfully, and `{:error, %Vnu.Error{}}` otherwise. Note that the `{:ok, %Vnu.Result{}}` return value does not mean necessarily that the document is valid. See `Vnu.valid?/1` and `Vnu.Message` for interpreting the result. ## Options - `:server_url` - The URL of [the Checker server](https://github.com/validator/validator). Defaults to `http://localhost:8888`. - `:filter` - A module implementing the `Vnu.MessageFilter` behavior that will be used to exclude messages matching the filter from the result. Defaults to `nil` (no excluded messages). - `:http_client` - A module implementing the `Vnu.HTTPClient` behaviour that will be used to make the HTTP request to the server. Defaults to `Vnu.HTTPClient.Hackney`. ## Examples iex> Vnu.validate_html(~S( ...> ...> ...>
...> ...> ...> ...> ...> ...>), server_url: System.get_env("VNU_SERVER_URL") || "http://localhost:8888") {:ok, %Vnu.Result{messages: [ %Vnu.Message{ type: :error, message: "Element “head” is missing a required instance of child element “title”.", extract: "=\"utf-8\">\n\n\n\n Vnu.validate_html("", server_url: "http://wrong-domain") {:error, %Vnu.Error{ reason: :unexpected_server_response, message: "Could not contact the server, got error: :nxdomain" }} """ @spec validate_html(String.t(), Keyword.t()) :: {:ok, Result.t()} | {:error, Error.t()} def validate_html(html, opts \\ []) when is_bitstring(html) and is_list(opts) do Validator.validate(html, Keyword.merge(opts, format: :html)) end @doc ~S""" Same as `validate_svg/2` but returns `%Vnu.Result{}` or raises `%Vnu.Error{}`. """ @spec validate_html!(String.t(), Keyword.t()) :: Result.t() | no_return() def validate_html!(html, opts \\ []) when is_bitstring(html) and is_list(opts) do Validator.validate!(html, Keyword.merge(opts, format: :html)) end @doc ~S""" Validates the given CSS document. See `validate_html/2` for the list of options and other details. ## Examples iex> Vnu.validate_css(".button { display: banana; }", server_url: System.get_env("VNU_SERVER_URL") || "http://localhost:8888") {:ok, %Vnu.Result{messages: [ %Vnu.Message{ type: :error, message: "“display”: “banana” is not a “display” value.", extract: ".button { display: banana; }\n", first_line: 1, last_line: 1, first_column: 20, last_column: 25, hilite_length: 6, hilite_start: 19, } ]}} iex> Vnu.validate_css("", server_url: "http://wrong-domain") {:error, %Vnu.Error{ reason: :unexpected_server_response, message: "Could not contact the server, got error: :nxdomain" }} """ @spec validate_css(String.t(), Keyword.t()) :: {:ok, Result.t()} | {:error, Error.t()} def validate_css(css, opts \\ []) when is_bitstring(css) and is_list(opts) do Validator.validate(css, Keyword.merge(opts, format: :css)) end @doc ~S""" Same as `validate_css/2` but returns `%Vnu.Result{}` or raises `%Vnu.Error{}`. """ @spec validate_css!(String.t(), Keyword.t()) :: Result.t() | no_return() def validate_css!(css, opts \\ []) when is_bitstring(css) and is_list(opts) do Validator.validate!(css, Keyword.merge(opts, format: :css)) end @doc ~S""" Validates the given SVG document. See `validate_html/2` for the list of options and other details. ## Examples iex> Vnu.validate_svg(~S( ...> ...> ), server_url: System.get_env("VNU_SERVER_URL") || "http://localhost:8888") {:ok, %Vnu.Result{messages: [ %Vnu.Message{ type: :info, message: "Using the preset for SVG + URL + HTML + MathML based on the root namespace." }, %Vnu.Message{ type: :error, sub_type: :fatal, message: "duplicate attribute (found “x”)", extract: "0.5cm\" x=\"0.5cm\" y=\"0.5cm\" hei", first_line: 4, last_line: 4, first_column: nil, last_column: 25, hilite_length: 1, hilite_start: 15, } ]}} iex> Vnu.validate_svg("", server_url: "http://wrong-domain") {:error, %Vnu.Error{ reason: :unexpected_server_response, message: "Could not contact the server, got error: :nxdomain" }} """ @spec validate_svg(String.t(), Keyword.t()) :: {:ok, Result.t()} | {:error, Error.t()} def validate_svg(svg, opts \\ []) when is_bitstring(svg) and is_list(opts) do Validator.validate(svg, Keyword.merge(opts, format: :svg)) end @doc ~S""" Same as `validate_svg/2` but returns `%Vnu.Result{}` or raises `%Vnu.Error{}`. """ @spec validate_svg!(String.t(), Keyword.t()) :: Result.t() | no_return() def validate_svg!(svg, opts \\ []) when is_bitstring(svg) and is_list(opts) do Validator.validate!(svg, Keyword.merge(opts, format: :svg)) end @doc ~S""" Checks if the results of `Vnu.validate_html/2`, `Vnu.validate_css/2`, or `Vnu.validate_svg/2` determined the document to be valid. ## Options - `:server_url` - The URL of [the Checker server](https://github.com/validator/validator). Defaults to `http://localhost:8888`. - `:fail_on_warnings` - Messages of type `:info` and subtype `:warning` will be treated as if they were validation errors. Their presence will mean the document is invalid. Defaults to `false`. - `:http_client` - A module implementing the `Vnu.HTTPClient` behaviour that will be used to make the HTTP request to the server. Defaults to `Vnu.HTTPClient.Hackney`. ## Examples iex> {:ok, result} = Vnu.validate_html("", server_url: System.get_env("VNU_SERVER_URL") || "http://localhost:8888") iex> Vnu.valid?(result) false iex> {:ok, result} = Vnu.validate_html(~S( ...> ...> ...> ...> ...>