Skip to main content

switchback_traits/model/
link.rs

1//! Intra-links, structural references, and link targets.
2
3/// Structural cross-reference in an entity body (schema `$ref`, protobuf FQN, etc.).
4///
5/// Serialized on the wire as part of [`StoredEntity`](super::entity::StoredEntity).
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct Reference {
8    /// Address of the referenced entity within the manual.
9    pub target: EntityRef,
10    /// How the reference is expressed in source (internal, external, inline, etc.).
11    pub kind: RefKind,
12}
13
14/// Classification of a structural reference in source.
15#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
16pub enum RefKind {
17    /// Reference kind not specified or unrecognized.
18    #[default]
19    Unspecified,
20    /// Reference to another entity in the same manual.
21    Internal,
22    /// Reference to an entity outside the manual (by FQN or URL).
23    External,
24    /// OpenAPI-style component reference.
25    Component,
26    /// Inline definition with no separate entity target.
27    Inline,
28}
29
30/// Address of an entity within a manual.
31///
32/// Wire-safe cross-reference key used in [`Reference`], [`IntraLink`] targets, and
33/// the [`ResolvedManual`](super::resolved::ResolvedManual) index.
34#[derive(Clone, Debug, PartialEq, Eq, Hash)]
35pub struct EntityRef {
36    /// Owning [`Module`](super::manual::Module) id string.
37    pub module: String,
38    /// Group id string within the contract.
39    pub group: String,
40    /// Entity category slug.
41    pub category: String,
42    /// Entity name within the group and category.
43    pub name: String,
44}
45
46/// Address of a group within a manual.
47#[derive(Clone, Debug, PartialEq, Eq, Hash)]
48pub struct GroupRef {
49    /// Owning module id string.
50    pub module: String,
51    /// Group id string within the contract.
52    pub group: String,
53}
54
55/// Address of a contract within a manual.
56#[derive(Clone, Debug, PartialEq, Eq, Hash)]
57pub struct ContractRef {
58    /// Owning module id string.
59    pub module: String,
60    /// [`ContractFamily`](crate::traits::ContractFamily) name.
61    pub family: String,
62    /// Contract spec version string.
63    pub version: String,
64}
65
66/// Address of a module within a manual.
67#[derive(Clone, Debug, PartialEq, Eq, Hash)]
68pub struct ModuleRef {
69    /// Module id string.
70    pub module: String,
71}
72
73/// Cross-manual reference by URI with optional inner target.
74#[derive(Clone, Debug, PartialEq, Eq)]
75pub struct ManualRef {
76    /// URI of the external manual (may be a file path or registry URL).
77    pub uri: String,
78    /// Version pin or label for the external manual, when specified.
79    pub version: String,
80    /// Optional entity or group target within the external manual.
81    pub inner: Option<ManualRefInner>,
82}
83
84/// Inner target of a [`ManualRef`] cross-manual link.
85#[derive(Clone, Debug, PartialEq, Eq)]
86pub enum ManualRefInner {
87    /// Link to a specific entity in the external manual.
88    Entity(EntityRef),
89    /// Link to a group overview in the external manual.
90    Group(GroupRef),
91}
92
93/// External URL link target (not resolved to an in-manual entity).
94#[derive(Clone, Debug, PartialEq, Eq, Hash)]
95pub struct ExternalUrl {
96    /// Absolute or relative URL string as authored.
97    pub url: String,
98}
99
100/// Prose-level link with anchor, resolved target, and raw author text.
101///
102/// Serialized on the wire as part of [`StoredEntity`](super::entity::StoredEntity).
103/// The `target` field uses wire-safe variants only at serialize time; see
104/// [`LinkTarget::Unresolved`].
105#[derive(Clone, Debug, PartialEq, Eq)]
106pub struct IntraLink {
107    /// Byte span locating the link within a prose field.
108    pub anchor: Anchor,
109    /// Resolved link destination.
110    pub target: LinkTarget,
111    /// Raw link text as authored in source prose.
112    pub raw: String,
113}
114
115/// Byte span within a prose field (`doc`, `fence_body`, etc.).
116#[derive(Clone, Debug, PartialEq, Eq)]
117pub struct Anchor {
118    /// Name of the field containing the link (e.g. `"doc"`, `"fence_body"`).
119    pub field: String,
120    /// Inclusive start byte offset within `field`'s UTF-8 content.
121    pub byte_start: u32,
122    /// Exclusive end byte offset within `field`'s UTF-8 content.
123    pub byte_end: u32,
124}
125
126/// Resolved intra-link destination.
127#[derive(Clone, Debug, PartialEq, Eq)]
128pub enum LinkTarget {
129    /// Link to an entity in the current or another module.
130    Entity(EntityRef),
131    /// Link to a group overview page.
132    Group(GroupRef),
133    /// Link to a contract within a module.
134    Contract(ContractRef),
135    /// Link to a module overview page.
136    Module(ModuleRef),
137    /// Link to another manual (possibly with an inner entity/group target).
138    Manual(ManualRef),
139    /// Link to an external URL.
140    External(ExternalUrl),
141    /// Link target could not be resolved during extraction.
142    ///
143    /// In-memory only; not serialized on the wire. Parsers may emit this during
144    /// extraction; codecs should reject or strip unresolved targets at serialize time.
145    Unresolved,
146}