#![allow(dead_code)]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SourceLoc {
pub file: String,
pub offset: usize,
pub line: u32,
}
impl SourceLoc {
pub fn from_offset(file: impl Into<String>, offset: usize, source: &str) -> Self {
let line = source[..offset.min(source.len())]
.chars()
.filter(|&c| c == '\n')
.count() as u32
+ 1;
SourceLoc {
file: file.into(),
offset,
line,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum NodeKind {
Function,
Alias,
TypeDef,
Module,
}
impl NodeKind {
pub fn prefix(&self) -> &'static str {
match self {
NodeKind::Function => "function",
NodeKind::Alias => "alias",
NodeKind::TypeDef => "type",
NodeKind::Module => "module",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Visibility {
Private,
Public,
Export,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum NodePayload {
Function {
params: Vec<(String, String)>,
returns: String,
},
Record {
fields: Vec<(String, String)>,
},
Alias {
underlying: String,
opaque: bool,
},
Union {
variants: Vec<(String, Option<String>)>,
},
Module {
exports: Vec<String>,
},
None,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Node {
pub id: String,
pub kind: NodeKind,
pub name: String,
pub module_path: Vec<String>,
pub visibility: Visibility,
pub doc: Option<String>,
pub source: Option<SourceLoc>,
pub payload: NodePayload,
}
impl Node {
pub fn make_id(kind: &NodeKind, module_path: &[String], name: &str) -> String {
if module_path.is_empty() {
format!("{}:{}", kind.prefix(), name)
} else {
format!("{}:{}/{}", kind.prefix(), module_path.join("/"), name)
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub enum EdgeKind {
HasField,
Returns,
ProducesType,
ParameterOf,
ConsumesType,
BelongsToModule,
Uses,
UsedBy,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Edge {
pub from: String,
pub to: String,
pub kind: EdgeKind,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Spg {
#[serde(rename = "@context")]
pub context: String,
pub package: String,
pub version: String,
pub nodes: Vec<Node>,
pub edges: Vec<Edge>,
}
impl Spg {
pub fn new(package: impl Into<String>, version: impl Into<String>) -> Self {
Spg {
context: "https://typr-lang.dev/spg/v1/context.jsonld".into(),
package: package.into(),
version: version.into(),
nodes: Vec::new(),
edges: Vec::new(),
}
}
pub fn add_node(&mut self, node: Node) {
self.nodes.push(node);
}
pub fn add_edge(&mut self, edge: Edge) {
self.edges.push(edge);
}
}