1#![allow(dead_code)]
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7pub struct SourceLoc {
8 pub file: String,
9 pub offset: usize,
10 pub line: u32,
11}
12
13impl SourceLoc {
14 pub fn from_offset(file: impl Into<String>, offset: usize, source: &str) -> Self {
16 let line = source[..offset.min(source.len())]
17 .chars()
18 .filter(|&c| c == '\n')
19 .count() as u32
20 + 1;
21 SourceLoc {
22 file: file.into(),
23 offset,
24 line,
25 }
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
31#[serde(rename_all = "snake_case")]
32pub enum NodeKind {
33 Function,
34 Alias,
35 TypeDef,
36 Module,
37 Variable,
38}
39
40impl NodeKind {
41 pub fn prefix(&self) -> &'static str {
42 match self {
43 NodeKind::Function => "function",
44 NodeKind::Alias => "alias",
45 NodeKind::TypeDef => "type",
46 NodeKind::Module => "module",
47 NodeKind::Variable => "variable",
48 }
49 }
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
54#[serde(rename_all = "snake_case")]
55pub enum Visibility {
56 Private,
57 Public,
58 Export,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
63#[serde(tag = "kind", rename_all = "snake_case")]
64pub enum NodePayload {
65 Function {
66 params: Vec<(String, String)>,
68 returns: String,
69 },
70 Record {
71 fields: Vec<(String, String)>,
73 },
74 Alias {
75 underlying: String,
76 opaque: bool,
77 },
78 Union {
79 variants: Vec<(String, Option<String>)>,
80 },
81 Module {
82 exports: Vec<String>,
83 },
84 Variable {
91 type_str: String,
92 },
93 None,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
102pub struct StdlibMeta {
103 pub tier: Option<String>,
106 pub param_docs: Vec<(String, String)>,
108 pub ret_doc: Option<String>,
110 pub coercion_notes: Option<String>,
112 pub examples: Vec<String>,
114 pub seealso: Vec<String>,
116 pub pkg: Option<String>,
118}
119
120impl StdlibMeta {
121 pub fn empty() -> Self {
122 StdlibMeta {
123 tier: None,
124 param_docs: Vec::new(),
125 ret_doc: None,
126 coercion_notes: None,
127 examples: Vec::new(),
128 seealso: Vec::new(),
129 pkg: None,
130 }
131 }
132
133 pub fn is_non_empty(&self) -> bool {
135 self.tier.is_some()
136 || !self.param_docs.is_empty()
137 || self.ret_doc.is_some()
138 || self.coercion_notes.is_some()
139 || !self.examples.is_empty()
140 || !self.seealso.is_empty()
141 || self.pkg.is_some()
142 }
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
147pub struct Node {
148 pub id: String,
150 pub kind: NodeKind,
151 pub name: String,
152 pub module_path: Vec<String>,
154 pub visibility: Visibility,
155 pub doc: Option<String>,
157 pub source: Option<SourceLoc>,
158 pub payload: NodePayload,
159 #[serde(skip_serializing_if = "Option::is_none")]
162 pub meta: Option<StdlibMeta>,
163}
164
165impl Node {
166 pub fn make_id(kind: &NodeKind, module_path: &[String], name: &str) -> String {
168 if module_path.is_empty() {
169 format!("{}:{}", kind.prefix(), name)
170 } else {
171 format!("{}:{}/{}", kind.prefix(), module_path.join("/"), name)
172 }
173 }
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
178#[serde(rename_all = "kebab-case")]
179pub enum EdgeKind {
180 HasField,
181 Returns,
182 ProducesType,
183 ParameterOf,
184 ConsumesType,
185 BelongsToModule,
186 Uses,
187 UsedBy,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
192pub struct Edge {
193 pub from: String,
194 pub to: String,
195 pub kind: EdgeKind,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct Spg {
201 #[serde(rename = "@context")]
203 pub context: String,
204 pub package: String,
205 pub version: String,
206 pub nodes: Vec<Node>,
207 pub edges: Vec<Edge>,
208}
209
210impl Spg {
211 pub fn new(package: impl Into<String>, version: impl Into<String>) -> Self {
212 Spg {
213 context: "https://typr-lang.dev/spg/v1/context.jsonld".into(),
214 package: package.into(),
215 version: version.into(),
216 nodes: Vec::new(),
217 edges: Vec::new(),
218 }
219 }
220
221 pub fn add_node(&mut self, node: Node) {
222 self.nodes.push(node);
223 }
224
225 pub fn add_edge(&mut self, edge: Edge) {
226 self.edges.push(edge);
227 }
228}