pub struct Document { /* private fields */ }Expand description
A fully-parsed Quillmark document. Serde routes through StoredDocument;
for the plate wire shape see Document::to_plate_json.
Implementations§
Source§impl Document
impl Document
pub fn set_quill_ref(&mut self, reference: QuillReference)
pub fn card_mut(&mut self, index: usize) -> Option<&mut Card>
Sourcepub fn push_card(&mut self, card: Card) -> Result<(), EditError>
pub fn push_card(&mut self, card: Card) -> Result<(), EditError>
Append a composable card. Its $kind must be a valid, non-reserved
composable kind (EditError::InvalidKindName /
EditError::ReservedKind otherwise) — the invariant for any card in
the cards list, enforced here so every entry path shares it.
Sourcepub fn insert_card(&mut self, index: usize, card: Card) -> Result<(), EditError>
pub fn insert_card(&mut self, index: usize, card: Card) -> Result<(), EditError>
Insert a composable card at index (index > len →
EditError::IndexOutOfRange; invalid $kind →
EditError::InvalidKindName / EditError::ReservedKind).
pub fn remove_card(&mut self, index: usize) -> Option<Card>
Sourcepub fn set_card_kind(
&mut self,
index: usize,
new_kind: impl Into<String>,
) -> Result<(), EditError>
pub fn set_card_kind( &mut self, index: usize, new_kind: impl Into<String>, ) -> Result<(), EditError>
Replace the $kind of the composable card at index.
Only the $kind metadata changes; the payload and body are untouched
(field-bag semantics). Old-schema fields linger in the bag; new-schema
fields are absent until set explicitly. Schema migration is the caller’s
responsibility — this is a structural primitive.
Returns EditError::IndexOutOfRange, EditError::InvalidKindName,
or EditError::ReservedKind on constraint violations.
Source§impl Document
impl Document
Sourcepub fn to_markdown(&self) -> String
pub fn to_markdown(&self) -> String
Emit canonical Quillmark Markdown from this document.
§Contract
-
Type-fidelity round-trip.
Document::from_markdown(&doc.to_markdown())returns aDocumentequal todocby value and by type variant.QuillValue::String("on")round-trips as a string, never as a bool.QuillValue::String("01234")round-trips as a string, never as an integer. This guarantee is the whole point of owning emission. -
Emit-idempotent.
to_markdownis a pure function ofdoc; two calls on the samedocreturn byte-equal strings.
Byte-equality with the original source is not guaranteed.
§Emission rules (§5.2)
- Line endings:
\nonly. CRLF normalization happens on import. - Every block is emitted as a
~~~card-yaml fence: a bare~~~opener, the$-prefixed system-metadata lines ($quill: <ref>for the root block,$kind: <kind>for composable cards) leading the YAML payload, the user-defined data fields, then a closing~~~. - Cards: one blank line before each, then the block, then the card body.
- Body: emitted verbatim after the root block (and after each card).
- Mappings and sequences: block style at every nesting level.
- Scalars (booleans, null, numbers, strings): delegated to
serde-saphyr, which emits the type-canonical form (true/false,null, bare numeric literal) and quotes strings only when the unquoted form would be misread (on/yes/off,null/~, numeric-looking strings, leading flow indicators,:runs, …). Quoting form is not stable — what matters is that the emitted scalar round-trips to the sameQuillValuevariant. This is the type-fidelity guarantee. - Multi-line strings: emitted as inline double-quoted scalars with
\nescapes; no|/>block forms.
§Open decisions (resolved)
-
Nested-map order.
QuillValueis backed byserde_json::Valuewhose object type (serde_json::Map) preserves insertion order when theserde_json/preserve_orderfeature is enabled (it is in this workspace). Insertion order is therefore preserved for nested maps at emit time. -
Empty containers.
- Empty object (
{}) → the key is omitted from emit entirely. - Empty array (
[]) → emitted askey: []\n.
- Empty object (
§What is preserved
- YAML comments: own-line and inline trailing comments round-trip at their source position. Comments whose host disappears at emit time (empty-mapping omission, programmatic field removal) degrade to own-line comments at the same indent so the comment text is preserved even when its position shifts.
!must_filltags: round-trip via thefillflag onPayloadItem::Field.
§What is lost
- Other custom tags (
!include,!env, …): the tag is dropped; the scalar value is preserved. - Original quoting style: strings are re-emitted in saphyr’s canonical form (plain when safe, quoted when ambiguous). The form chosen for emit may not match the form in the source.
Source§impl Document
impl Document
Sourcepub fn from_main_and_cards(
main: Card,
cards: Vec<Card>,
warnings: Vec<Diagnostic>,
) -> Self
pub fn from_main_and_cards( main: Card, cards: Vec<Card>, warnings: Vec<Diagnostic>, ) -> Self
Create a Document from a pre-built main card and composable cards.
main must carry $quill; composable cards must not.
pub fn from_markdown(markdown: &str) -> Result<Self, ParseError>
pub fn from_markdown_with_warnings( markdown: &str, ) -> Result<ParseOutput, ParseError>
pub fn main(&self) -> &Card
pub fn main_mut(&mut self) -> &mut Card
Sourcepub fn quill_reference(&self) -> QuillReference
pub fn quill_reference(&self) -> QuillReference
The $quill reference from the root block. Always present on parsed documents.
pub fn cards(&self) -> &[Card]
pub fn cards_mut(&mut self) -> &mut [Card]
Sourcepub fn warnings(&self) -> &[Diagnostic]
pub fn warnings(&self) -> &[Diagnostic]
Non-fatal warnings from the parse; empty for programmatically built documents.
Sourcepub fn to_plate_json(&self) -> Value
pub fn to_plate_json(&self) -> Value
Serialize to the JSON wire shape consumed by backend plates. This is
the only place in quillmark-core that produces this shape:
{
"$quill": "<ref>",
"$body": "<global-body>",
"$cards": [{ "$kind": "<tag>", "$body": "<card-body>", "<field>": <value>, ... }],
"<field>": <value>, ...
}$-prefixed keys carry document-level metadata (quill ref, body
text, card list, card kind). User payload fields stay flat at the
root — they cannot collide with $ keys because user field names are
never $-prefixed (they match [A-Za-z_][A-Za-z0-9_]*).