# `Riddler.Finding`
[🔗](https://github.com/riddler/riddler-ex/blob/v0.4.0/lib/riddler/finding.ex#L1)

One reason something was refused.

A finding is the unit every refusal in this package reports: a template that
names a construct outside the template subset, and later a document whose
vocabulary is not admitted. Refusals return a list of findings rather than
the first one, so that an author fixing what they wrote learns everything
wrong with it in a single pass.

The fields stay few, and one is added only where a host would otherwise have
to read the `:message` to get at something it needs:

  * `:code` - a stable, machine-readable reason. Hosts switch on it; it does
    not change when the wording does.
  * `:message` - the human sentence, naming what was refused and, where the
    refusal has a place in some source text, where it appeared.
  * `:field` - what the finding is about: the name of the refused construct
    for a template, the offending field for a document. `nil` when the
    refusal is about the input as a whole.
  * `:node_key` - the key of the document node the finding belongs to, and
    always a string or `nil`. It is `nil` wherever there is no key a host
    can look a node up by: a template finding, because a template is
    compiled on its own without the document that carries it; a finding
    about the envelope, which is the document's and not any one node's; and
    a node whose key is absent or is not a string. A key of the wrong form
    is named in the `message` rather than carried here, because a host reads
    this field to find the node the author has to fix and a key that is not
    a string is not a name it can find one by.
  * `:position` - where in some source text the refusal is, as
    `%{line: line, column: column}`, both one-based. The column counts in
    the unit of the parser that located the refusal, and this package
    converts neither: a column the template parser gave counts bytes, and a
    column the condition compiler or the evaluator gave counts characters.
    The two differ wherever a multi-byte character stands before the place
    on its line, so a host that maps a column onto an editor offset reads
    the finding's code to know which it holds. Five places in this package
    set it: the two template refusal clauses in `Riddler.Template`, the
    `document.invalid_template` finding that re-reports a template refusal
    against the template a document node writes, which carries the position
    of the refusal it wraps, the `document.invalid_condition` finding, which
    carries the place the condition compiler gave for a condition that does
    not parse and nothing for a condition that never reached the parser, and
    the `response.undecidable` finding, which carries the place the condition
    compiler or the evaluator gave for the condition it is about and nothing
    where neither gave one. The first three give bytes and the last two give
    characters. Every other finding leaves it `nil` - the
    document checks, a field refused for not being template source at all
    (which carries that same code, so the code alone does not say whether a
    span is there), and the other `response.*` findings.
    `document.invalid_pattern` is one of those by decision rather than by
    defect: the regular expression compiler answers a byte count into the
    expression this package compiles rather than a line and a column, and
    across the refusals run that count lands at the defect for some and at
    the end of the input for others, and is moved, or its reason replaced,
    by the anchors this package adds. A place derived from it would be right
    for some refusals under that code and wrong for others, which is worse
    for a host than none; the comment above `compile_pattern/1` in the
    internal Riddler.Screens.Compilers module records what was run. Where there is a
    position the `:message` names
    it too and goes on naming it, so that a person reading a finding reads
    one sentence; this field is the same fact in the form an editor can act
    on without parsing that sentence.

## Examples

    iex> finding = %Riddler.Finding{
    ...>   code: "template.tag_not_allowed",
    ...>   message: ~s[the tag "include" is not in the template subset (line 1, column 3)],
    ...>   field: "include",
    ...>   position: %{line: 1, column: 3}
    ...> }
    iex> {finding.node_key, finding.position}
    {nil, %{line: 1, column: 3}}

# `position`

```elixir
@type position() :: %{line: pos_integer(), column: pos_integer()}
```

A place in some source text: a one-based line and a one-based column. The
column counts bytes where the template parser located the place and
characters where the condition compiler or the evaluator did; the
`:position` field in the moduledoc says which finding gives which.

# `t`

```elixir
@type t() :: %Riddler.Finding{
  code: String.t(),
  field: String.t() | nil,
  message: String.t(),
  node_key: String.t() | nil,
  position: position() | nil
}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
