Adapters¶
Status: draft
Proposals by Claude – not binding until Daniel approves them.
An adapter knows which objects exist in its format. It turns the text of a source file into a tree of elements, each with a structural selector, a text range and the text used for the fingerprint.
@dataclass(frozen=True)
class Element:
selector: str # "md:heading:Career/Advisor"
kind: str # "heading", "paragraph", "need", ...
label: str # short text for UIs and the CLI
start: int # character offsets in the source
end: int
line: int # 1-based, for humans and editors
text: str # source text of the element (fingerprint input)
children: tuple["Element", ...] = ()
class Adapter(Protocol):
name: str # "md", "rst", "text"
suffixes: tuple[str, ...] # (".md",), (".rst",), (".txt",)
def elements(self, source: str, path: str) -> list[Element]: ...
Adapters are pure: no file access, no state. That keeps them fast to test with golden files (source in, element list as JSON out) and lets the Sphinx extension reuse them later.
Structural selectors¶
A selector is a string <adapter>:<kind>:<path>. It is what users see in the
CLI and what the file format stores.
Adapter |
Selector |
Element |
|---|---|---|
md |
|
the section under that heading path, including its content |
md |
|
the 2nd paragraph inside that section |
md |
|
list item, table row, code block – numbered per section |
md |
|
a frontmatter field |
rst |
|
as in Markdown |
rst |
|
a need, found by id – the most robust selector there is |
rst |
|
one option of a need |
rst |
|
the first |
text |
|
plain text |
Heading paths survive moves of whole sections and edits in other sections.
The counter ( |
Markdown¶
Parser: markdown-it-py (CommonMark + tables), token maps give line ranges; offsets come from the line ranges.
Elements: heading sections, paragraphs, list items (nested), table rows, code blocks, frontmatter fields (YAML keys at the top level).
rST and Sphinx-Needs¶
docutils keeps source lines on every node. Unknown directives and roles
(Sphinx, Sphinx-Needs, any extension) are registered as generic
placeholders, so a file parses without |
Proposal: read them from |
Plain text¶
Paragraphs are blocks separated by blank lines; lines are a second level. Everything else is free text selection.
Free text selection¶
Selecting a word stores the structural selector of the element that contains
it plus a |