pedant_graph/node.rs
1//! A graph node: one structural entity, its language, and where its bytes sit.
2
3use std::sync::Arc;
4
5use pedant_types::{Language, SourceSpan};
6use serde::Serialize;
7
8use crate::id::GraphNodeId;
9
10/// What kind of entity a node is.
11///
12/// The categories are stable graph concepts. The attribute strings are
13/// language-declared vocabulary, so another producer may add a level or a
14/// declaration name without changing the schema. A producer emits a non-empty
15/// lower-snake-case value.
16#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
17#[serde(tag = "category", rename_all = "snake_case")]
18pub enum GraphNodeKind {
19 /// One source artifact, qualified by the unit that instantiates it.
20 File,
21 /// A namespace that owns other entities.
22 Container {
23 /// The language's name for this container level.
24 level: Arc<str>,
25 },
26 /// A callable entity.
27 Function {
28 /// The language's name for this callable declaration.
29 declaration: Arc<str>,
30 },
31 /// A type entity.
32 Type {
33 /// The language's name for this type declaration.
34 declaration: Arc<str>,
35 },
36 /// A named value entity.
37 Value {
38 /// The language's name for this value declaration.
39 declaration: Arc<str>,
40 },
41}
42
43/// Where a node's bytes sit, when it has any.
44///
45/// A span identifies the unit-qualified file node that holds the bytes. That is
46/// a source association, never a containment parent.
47#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
48#[serde(tag = "kind", rename_all = "snake_case")]
49pub enum GraphNodeLocation {
50 /// The node is the source artifact itself.
51 File {
52 /// The normalized repository-relative path.
53 path: Arc<str>,
54 },
55 /// The node is declared at one range of one file node's bytes.
56 Span {
57 /// The unit-qualified file node holding the declaration.
58 file: GraphNodeId,
59 /// The exact declaration range.
60 span: SourceSpan,
61 },
62}
63
64/// One structural entity of a code graph.
65#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
66pub struct GraphNode {
67 id: GraphNodeId,
68 language: Language,
69 name: Arc<str>,
70 kind: GraphNodeKind,
71 location: Option<GraphNodeLocation>,
72}
73
74/// Everything a projection states about one node before it has an identity.
75pub(crate) struct NodeDraft {
76 /// The language of the unit the node belongs to.
77 pub(crate) language: Language,
78 /// The declared name, or the normalized path for a file node.
79 pub(crate) name: Arc<str>,
80 /// What kind of entity the node is.
81 pub(crate) kind: GraphNodeKind,
82 /// Where the node's bytes sit, when it has any.
83 pub(crate) location: Option<GraphNodeLocation>,
84}
85
86impl GraphNode {
87 pub(crate) fn new(id: GraphNodeId, draft: NodeDraft) -> Self {
88 Self {
89 id,
90 language: draft.language,
91 name: draft.name,
92 kind: draft.kind,
93 location: draft.location,
94 }
95 }
96
97 /// This node's dense identity, equal to its position in the graph.
98 pub fn id(&self) -> GraphNodeId {
99 self.id
100 }
101
102 /// The language of the unit this node belongs to.
103 pub fn language(&self) -> Language {
104 self.language
105 }
106
107 /// The declared name, or the normalized path for a file node.
108 pub fn name(&self) -> &str {
109 &self.name
110 }
111
112 /// What kind of entity this node is.
113 pub fn kind(&self) -> &GraphNodeKind {
114 &self.kind
115 }
116
117 /// Where this node's bytes sit, when it has any.
118 pub fn location(&self) -> Option<&GraphNodeLocation> {
119 self.location.as_ref()
120 }
121}