Parse once, reporting native failures before enabled lint failures.
AsciiDoc
:= { title : Str, blocks : List(Block) }
Pure AsciiDoc block parsing and HTML rendering.
from_quote : Str -> Try(AsciiDoc, [BadQuotedBytes(Str)])
A quoted document uses the default pure preprocessing and lint rules.
attributes : List(Attribute) -> Attributes
Construct independent ordered bindings for a manually assembled block.
materialize_attributes : Attributes -> List(Attribute)
Return all bindings as an ordered list for inspection or replacement.
render_inline_attributes : Str, Attributes -> Str
Render inline text using a block's shared attribute bindings.
default_options : Options
Default attributes, includes disabled and include depth limited to 16.
Parse a UTF-8 document with default preprocessing options.
parse_with : Str, Options -> Try(Document, [Unsupported(Error), InvalidAsciiDoc(Error)])
Parse using only caller-supplied include sources; never reads files.
render_inline : Str, List(Attribute) -> Str
Render inline substitutions with caller-supplied attributes.
Render an embedded HTML document with shared IDs and footnotes.
select_include : Str, Str -> IncludeSelection
Select the lines of source that an include directive with this
attribute list selects, such as lines=1..4,indent=0 or tag=example.
include:: expansion calls the same code, so a tool that expands
includes itself selects exactly the lines this package would. Both
select what Asciidoctor 2.0.23 selects.
The attributes it reads are lines, tag, tags and indent; others,
such as leveloffset, are ignored. The first of lines=, tag= and
tags= that is present wins, even with an empty value. An unquoted
None value leaves an attribute unset, and attribute references such
as {range} are not expanded.
lines=: entries separated by,, or by;when there is no comma, each a lineN, a rangeN..M, or an open rangeN..orN..-1. An emptylines=selects every line.tag=names one tag, even one containing;or,.tags=names several, separated likelines=entries.!nameexcludes a tag,*selects the lines inside any tag and**every line; the marker lines themselves are left out. Tags nest, and the innermost open tag decides whether a line is selected, sotags=x;!yselectsxinsidey. An emptytag=ortag=!, or atags=naming no tag, selects every line and keeps the markers.- A tag marker is the first
tag::NAME[]orend::NAME[]on a line that starts a word and whose[]ends the line or is followed by a space. NAME has no whitespace. So"tag::x[]"in a string literal andmy_tag::x[]are not markers. indent=N: finds the fewest leading whitespace characters on any nonempty selected line, counting a tab like a space, and removes that many from each nonempty line. It then indents each nonempty line by N spaces, and leaves empty lines empty. So withindent=0, a line indented by one tab and a line indented by two spaces each lose one character. An emptyindent=dedents likeindent=0, and a negative N changes nothing.
The source is read as Asciidoctor reads an included file that isn't
AsciiDoc: trailing whitespace is kept, so a line of only spaces counts
toward indent=, and the selected lines keep it wherever they land in
the document. When include:: expansion includes an AsciiDoc file
(.adoc, .asciidoc, .asc, .ad or .txt), it first removes
trailing whitespace from each line, as Asciidoctor does. Tabs are not
expanded, as in a document that doesn't set tabsize. For a document
that does, use AsciiDoc.select_include_with.
expect AsciiDoc.select_include("\t// tag::x[]\n\tfn = |x|\n\n\t\tx\n\t// end::x[]\n", "tag=x,indent=0") == { text: "fn = |x|\n\n\tx", lines: [2, 3, 4], problems: [] }
select_include_with : Str, Str, IncludeContext -> IncludeSelection
AsciiDoc.select_include for a directive in a document described by
context. With tabsize set, indent= first expands each tab to the
next multiple of tabsize columns, counting each character before it
as one column, as include:: expansion does in such a document. A tab
size above 1024 counts as 1024.
expect AsciiDoc.select_include_with("\t\tx\n\t y", "indent=0", { tabsize: 4 }).text == " x\ny"
Lints
:= { unexpanded_includes : Bool ?? True }
Reject active include directives that were left unexpanded.
ValidationProps
:= {
source : Str,
name : Str ?? "<literal>",
lints : Lints ?? {},
includes : List({ path : Str, source : Str }) ?? [],
attributes : List(Attribute) ?? [],
max_depth : U64 ?? 16,
expand_includes : Bool ?? False,
}
Source and pure preprocessing options for checked conversion. Includes are supplied explicitly; validation never reads files.
Parsed title and source-preserving blocks.
Attribute name and its string value.
Attributes : Attributes
Immutable ordered bindings shared by parsed block snapshots.
Block
:= [Paragraph(Str), Section({ level : U64, title : Str, blocks : List(Block) }), Listing(Str), Literal(Str), ThematicBreak, Rich({ context : Str, source : Str, title : Str, style : Str, id : Str, attrs : Attributes, blocks : List(Block), level : U64 })]
A source block; Rich retains metadata and nested block contexts.
is_eq : _
Compare source blocks, including metadata and nested content.
A located parse error: UTF-8 byte offset and one-based line.
Options : { includes : List({ path : Str, source : Str }), attributes : List(Attribute), max_depth : U64, expand_includes : Bool }
Virtual sources and initial attributes for bounded preprocessing.
IncludeSelection : { text : Str, lines : List(U64), problems : List(IncludeProblem) }
The lines an include:: directive selects from its source, as returned
by AsciiDoc.select_include.
text: the selected lines after anyindent=, joined with LF and with no final LF. As in include expansion, a CR that ends a line and a leading byte order mark are removed.lines: the one-based source line number of each selected line, in order. A final LF ends the last line rather than starting a new one, and an empty source has no lines, as in Asciidoctor.problems: eachAsciiDoc.IncludeProblemfound, once, in the order found. An empty list means the selection is clean.
expect AsciiDoc.select_include("one\ntwo\nthree\n", "lines=2..3") == { text: "two\nthree", lines: [2, 3], problems: [] }
IncludeProblem : [MissingTag(Str), UnclosedTag(Str), UnmatchedEnd(Str), InvalidLines(Str), EmptySelection]
Something in an include's selection that Asciidoctor warns about, or that it selects silently but is probably a mistake. Selection itself is Asciidoctor's, so a strict caller rejects any problem and a lenient caller ignores them.
Tag markers matter only when tag= or tags= selects and lines= is
absent. As in Asciidoctor, the open tags form a stack, which holds the
tags the selector names and, when it uses * or !*, every other tag
too. So does !** when the first other tag named is negated, as in
!**;!x. The first three problems are exactly Asciidoctor's warnings:
MissingTag(name):tag=ortags=requestsnamepositively (not*,**or!name), but notag::name[]marker opens it. Asciidoctor warns that the tag is not found.UnclosedTag(name):nameis still open when the source ends. Asciidoctor warns that it detected an unclosed tag. A re-opened tag nests, sotag::x[]twice needsend::x[]twice.UnmatchedEnd(name): anend::name[]marker for a tag the selector names whilenameis not the innermost open tag. Asciidoctor warns of a mismatched end tag, which closes the innermost opennamewithout changing what is selected, or of an unexpected one whennameis not open. It ignores such an end silently for a tag that only a wildcard tracks, which may leave that tag unclosed.
Asciidoctor gives no warning for the other two:
InvalidLines(entry): an entry oflines=, without surrounding spaces, that is notN,N..Mwith N ≤ M,N..orN..-1, where N and M are plain decimal numbers and N is at least 1; or one whose first line is past the end of the source. Asciidoctor reads these entries without a warning:4abcselects line 4 and+2line 2, a reversed range such as4..2selects nothing (so a list of only reversed ranges selects every line), and a start of 0 or less selects nothing at all. A range that only partly runs past the end is not a problem.EmptySelection: no lines are selected, including from an empty source.
When lines= is present, tag= and tags= are ignored, as in
Asciidoctor, and report nothing.
expect AsciiDoc.select_include("a\n// tag::x[]\nb\n", "tag=x").problems == [UnclosedTag("x")]
IncludeContext
:= { tabsize : U64 ?? 0 }
The document an include directive is in, as far as selection depends
on it. tabsize is the document's tabsize attribute where the
directive appears, read as a number; 0, the default, expands no tabs.
Asciidoctor reads it from the document only, never from the
directive's own attribute list.