Documentation
¶
Overview ¶
Package markdown parses a SKILL.md body into a small structured view, using goldmark (the established Go Markdown parser) instead of hand-rolled regexes. Doing the parsing properly means code fences, headings, lists, tables, links, and code spans are AST facts — so, for example, a "#" comment inside a ```code block``` is no longer mistaken for a heading.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Doc ¶
type Doc struct {
Sections []Section
Prose string // body text with code blocks and code spans blanked
Links []string // link destinations and code-span contents (ref candidates)
// CodeSpans is the contents of every inline code span, in document order.
//
// Links already carries these, mixed with link destinations, because a consumer
// resolving references wants both. A consumer asking a different question — which
// of these is a command this document claims its repository supports — cannot use
// that slice without treating destinations as candidates. Separate rather than
// splitting Links, which four consumers read.
CodeSpans []string
HasOrderedList bool
// HasCodeBlock reports a fenced or indented code block, never an inline code span.
//
// It is a derived fact, and consumers use it to decide whether a check applies at
// all -- skillsaw's dim 3 and adh's failure-handling factor both ask it before
// deducting. An obligation comes with that use, and it is not enforceable here:
// a consumer that suppresses anything on this predicate must say so and say why.
// A check that silently declines is indistinguishable from one that found nothing.
// What gets suppressed is the consumer's choice -- a deduction, a whole check, or
// nothing at all; the reason is not.
HasCodeBlock bool
}
Doc is the parsed view of a SKILL.md body.
func Parse ¶
Parse parses a Markdown body. It is pure: same input, same Doc. GFM is enabled so tables are recognized.
It parses twice, over the same bytes, and the second parse exists for one reason: **a fenced code block written inside an HTML block is not a code block.** A `<Good>` tag with no blank line after it opens a CommonMark type-7 HTML block that runs to the next blank line, swallowing any fence inside it — so `prose` never sees a FencedCodeBlock to blank, and the example's own code reaches Prose as though the skill had instructed it. `<Good>`/`<Bad>` wrappers around examples are a documented convention, so this is the common case rather than a corner.
The second parse removes the HTML block parser, which turns those fences back into fences. It is used for Prose and HasCodeBlock — the two answers about *what code this document contains* — and deliberately not for Sections, Links, or HasOrderedList, whose answers are about document structure, where an HTML block genuinely is one block.
Blanking the whole HTML block was the obvious one-line alternative and is wrong: `<Good>Always validate input.</Good>` is a real instruction that reaches Prose correctly today, and blanking the block would destroy it. Scanning the block's raw lines for fence delimiters was the other, and it is a second fence implementation in the package whose first sentence says it does not have one.