use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Language {
Python,
TypeScript,
JavaScript,
Go,
Rust,
Java,
Kotlin,
Ruby,
CSharp,
Cpp,
C,
Php,
Scala,
Swift,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SymbolKind {
File,
Module,
Namespace,
Class,
Interface,
Trait,
Enum,
Struct,
Function,
Method,
Field,
Variable,
Constant,
Import,
TypeAlias,
Process,
Contract,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EdgeKind {
Contains,
Imports,
Calls,
Instantiates,
Inherits,
Implements,
References,
Defines,
Uses,
ParticipatesIn,
Serves,
Consumes,
Publishes,
Subscribes,
Reads,
Writes,
}
impl EdgeKind {
pub fn as_str(&self) -> &'static str {
match self {
EdgeKind::Contains => "contains",
EdgeKind::Imports => "imports",
EdgeKind::Calls => "calls",
EdgeKind::Instantiates => "instantiates",
EdgeKind::Inherits => "inherits",
EdgeKind::Implements => "implements",
EdgeKind::References => "references",
EdgeKind::Defines => "defines",
EdgeKind::Uses => "uses",
EdgeKind::ParticipatesIn => "participates_in",
EdgeKind::Serves => "serves",
EdgeKind::Consumes => "consumes",
EdgeKind::Publishes => "publishes",
EdgeKind::Subscribes => "subscribes",
EdgeKind::Reads => "reads",
EdgeKind::Writes => "writes",
}
}
}
impl std::fmt::Display for EdgeKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RepoId(pub String);
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Commit(pub String);
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct GlobalSymbolId {
pub scheme: String,
pub package_manager: String,
pub package: String,
pub version: String,
pub descriptor: String,
}
impl GlobalSymbolId {
pub fn render(&self) -> String {
format!(
"{} {} {} {} {}",
self.scheme, self.package_manager, self.package, self.version, self.descriptor
)
}
pub fn is_package_managed(&self) -> bool {
self.package_manager != "."
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Position {
pub line: u32,
pub column: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Range {
pub start: Position,
pub end: Position,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Symbol {
pub id: GlobalSymbolId,
pub name: String,
pub kind: SymbolKind,
pub language: Language,
pub repo: RepoId,
pub file_path: String,
pub range: Range,
pub signature: Option<String>,
pub docstring: Option<String>,
#[serde(default)]
pub fingerprint: Option<Fingerprint>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Fingerprint {
pub sig: u64,
pub body: u64,
pub shape: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Edge {
pub src: GlobalSymbolId,
pub dst: GlobalSymbolId,
pub kind: EdgeKind,
pub confidence: f32,
pub cross_repo: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scip_id_renders_and_detects_managed() {
let id = GlobalSymbolId {
scheme: "scip-python".into(),
package_manager: "pip".into(),
package: "acme".into(),
version: "1.4.0".into(),
descriptor: "acme/foo/bar().".into(),
};
assert_eq!(id.render(), "scip-python pip acme 1.4.0 acme/foo/bar().");
assert!(id.is_package_managed());
let local = GlobalSymbolId {
package_manager: ".".into(),
..id
};
assert!(!local.is_package_managed());
}
}