Internal helper used by the HEEx-scanning Rbtz Credo checks.
Template extraction
templates/1 returns every ~H sigil string and every .heex template
referenced via embed_templates as a list of {contents, line_fn} tuples.
line_fn is a function that takes an offset (0-based line index into
contents) and returns the line number in the .ex source file to report
an issue against.
For ~H sigils, line_fn.(off) = sigil_start_line + off.
For embed_templates, the template contents live in a separate
.html.heex file — Credo's format_issue can only reference lines that
exist in the .ex source file, so line_fn.(_) always returns the line
of the embed_templates call.
Body capture
capture_interpolation/1 and capture_string/1 extract the inside of
class={...} and class="..." attribute bodies respectively, tracking
string/escape state so braces nested inside strings or escaped quotes are
handled correctly.
Tag walking
walk_tags/3 walks a template line-by-line, tracking multi-line open tags,
and returns one record per fully-opened tag ({open_line, trigger, presence}).
Callers provide a tag-open detector and a keyword list of attribute detectors;
the helper centralises the state machine the various phx-* checks share.
Summary
Functions
Captures the content of a {...} interpolation body.
Captures the content of a "..." string literal body.
Returns the number of \n bytes in binary.
Returns true when text contains an id= (or id / id={) attribute
as a standalone token — not as a tail of a hyphenated name such as
data-id= or aria-labelledby=.
Returns [{contents, line_fn}] for every HEEx template embedded in the file.
Walks a HEEx template line-by-line and returns one record per fully-opened tag.
Functions
Captures the content of a {...} interpolation body.
Call with input pointing to the first byte inside the {. Consumes until
the matching close brace at depth 0 and returns {:ok, captured}, or
:unterminated if the input runs out first. Braces inside string literals
(with backslash escapes) do not affect the depth counter.
Captures the content of a "..." string literal body.
Call with input pointing to the first byte inside the opening ". Consumes
until the closing (unescaped) " and returns {:ok, captured}, or
:unterminated if the input runs out first. The captured content preserves
backslash escapes verbatim.
Returns the number of \n bytes in binary.
Checks that compute a line number by slicing into the template via
binary_part/3 use this to translate a byte offset into a line offset.
Returns true when text contains an id= (or id / id={) attribute
as a standalone token — not as a tail of a hyphenated name such as
data-id= or aria-labelledby=.
Shared between the phx_*_without_id checks and the
LiveViewFormCanBeRehydrated check so the regex lives in one place.
Returns [{contents, line_fn}] for every HEEx template embedded in the file.
Walks a HEEx template line-by-line and returns one record per fully-opened tag.
detect_open.(line) returns {trigger, rest_of_line} for a tag opener it
wants to track, or nil to skip the line. attr_detectors is a keyword list
of {key, detector_fn} — each detector_fn.(text) is called with the
current text slice and returns truthy if the attribute appears. Presence is
sticky: once an attribute is seen on any line of a tag's body, it stays true.
Returns [{open_line, trigger, presence_map}] in source order, where
presence_map has one boolean per key in attr_detectors.
Limitation: splits a tag at the first > on any line, so > characters
inside attribute strings can prematurely close a tag. This matches the
behaviour of the pre-extraction per-check scanners.