#![forbid(unsafe_code)]
use serde::{Deserialize, Serialize};
mod convert;
pub mod edge;
pub mod vertex;
pub type Id = lsp::NumberOrString;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Entry {
pub id: Id,
#[serde(flatten)]
pub element: Element,
}
impl Entry {
pub fn new(id: Id, element: impl Into<Element>) -> Entry {
let element = element.into();
Entry { id, element }
}
pub fn id(&self) -> Id {
self.id.to_owned()
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(tag = "type")]
pub enum Element {
Vertex(Vertex),
Edge(Edge),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(tag = "label")]
pub enum Vertex {
Project(vertex::Project),
Document(vertex::Document),
Range(vertex::Range),
ResultSet,
#[serde(rename = "$event")]
Event(vertex::Event),
Moniker(vertex::Moniker),
PackageInformation(vertex::PackageInformation),
MetaData(vertex::MetaData),
DefinitionResult,
DeclarationResult,
HoverResult { result: lsp::Hover },
ReferenceResult,
ImplementationResult,
TypeDefinitionResult,
FoldingRangeResult { result: Vec<lsp::FoldingRange> },
DocumentLinkResult { result: Vec<lsp::DocumentLink> },
DocumentSymbolResult {
result: vertex::DocumentSymbolResult,
},
DiagnosticResult { result: Vec<lsp::Diagnostic> },
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(tag = "label")]
pub enum Edge {
Contains(edge::E1N),
Next(edge::E11),
Item(edge::Item),
Moniker(edge::E11),
NextMoniker(edge::E11),
PackageInformation(edge::E11),
#[serde(rename = "textDocument/definition")]
Definition(edge::E11),
#[serde(rename = "textDocument/declaration")]
Declaration(edge::E11),
#[serde(rename = "textDocument/hover")]
Hover(edge::E11),
#[serde(rename = "textDocument/references")]
References(edge::E11),
#[serde(rename = "textDocument/implementation")]
Implementation(edge::E11),
#[serde(rename = "textDocument/typeDefinition")]
TypeDefinition(edge::E11),
#[serde(rename = "textDocument/foldingRange")]
FoldingRange(edge::E11),
#[serde(rename = "textDocument/documentLink")]
DocumentLink(edge::E11),
#[serde(rename = "textDocument/documentSymbol")]
DocumentSymbol(edge::E11),
#[serde(rename = "textDocument/diagnostic")]
Diagnostic(edge::E11),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::edge::*;
use crate::vertex::*;
use lsp::{HoverContents, LanguageString, MarkedString, Position};
fn assert_serde(text: &str, entry: Entry) {
assert_eq!(
serde_json::from_str::<serde_json::Value>(text).unwrap(),
serde_json::to_value(&entry).unwrap()
);
assert_eq!(serde_json::from_str::<Entry>(text).unwrap(), entry);
}
#[test]
fn project() {
let text = r#"{ "id": 1, "type": "vertex", "label": "project", "resource": "file:///Users/dirkb/tsconfig.json", "kind": "typescript"}"#;
let entry = Entry::new(
Id::Number(1),
vertex::Project {
resource: Some(lsp::Url::parse("file:///Users/dirkb/tsconfig.json").unwrap()),
kind: "typescript".to_owned(),
contents: None,
},
);
assert_serde(text, entry);
}
#[test]
fn document() {
let text = r#"{ "id": 1, "type": "vertex", "label": "document", "uri": "file:///Users/dirkb/sample.ts", "languageId": "typescript" }"#;
let entry = Entry::new(
Id::Number(1),
vertex::Document {
uri: lsp::Url::parse("file:///Users/dirkb/sample.ts").unwrap(),
language_id: "typescript".to_owned(),
contents: None,
},
);
assert_serde(text, entry);
}
#[test]
fn event_document() {
let text = r#"[
{ "id": 5, "type": "vertex", "label": "$event", "kind": "begin", "scope": "document", "data": 4 },
{ "id": 53, "type": "vertex", "label": "$event", "kind": "end", "scope": "document", "data": 4 }
]"#;
let elems = vec![
Entry::new(
Id::Number(5),
vertex::Event {
kind: EventKind::Begin,
scope: EventScope::Document,
data: Id::Number(4),
},
),
Entry::new(
Id::Number(53),
vertex::Event {
kind: EventKind::End,
scope: EventScope::Document,
data: Id::Number(4),
},
),
];
assert_eq!(
serde_json::from_str::<serde_json::Value>(&text).unwrap(),
serde_json::to_value(&elems).unwrap()
);
assert_eq!(serde_json::from_str::<Vec<Entry>>(&text).unwrap(), elems);
}
#[test]
fn event_project() {
let text = r#"[
{ "id": 3, "type": "vertex", "label": "$event", "kind": "begin", "scope": "project", "data": 2 },
{ "id": 55, "type": "vertex", "label": "$event", "kind": "end", "scope": "project", "data": 2 }
]"#;
let elems = vec![
Entry::new(
Id::Number(3),
vertex::Event {
kind: EventKind::Begin,
scope: EventScope::Project,
data: Id::Number(2),
},
),
Entry::new(
Id::Number(55),
vertex::Event {
kind: EventKind::End,
scope: EventScope::Project,
data: Id::Number(2),
},
),
];
assert_eq!(
serde_json::from_str::<serde_json::Value>(&text).unwrap(),
serde_json::to_value(&elems).unwrap()
);
assert_eq!(serde_json::from_str::<Vec<Entry>>(&text).unwrap(), elems);
}
#[test]
fn moniker_vertex() {
let text = r#"{ "id": 12, "type": "vertex", "label": "moniker", "kind": "export", "scheme": "tsc", "identifier": "lib/index:func" }"#;
let entry = Entry::new(
Id::Number(12),
vertex::Moniker {
kind: Some(MonikerKind::Export),
scheme: "tsc".to_owned(),
identifier: "lib/index:func".to_owned(),
},
);
assert_serde(text, entry);
}
#[test]
fn moniker_edge() {
let text = r#"{ "id": 13, "type": "edge", "label": "moniker", "outV": 11, "inV": 12 }"#;
let entry = Entry::new(
Id::Number(13),
Edge::Moniker(E11 {
out_v: Id::Number(11),
in_v: Id::Number(12),
}),
);
assert_serde(text, entry);
}
#[test]
fn next_moniker() {
let text = r#"{ "id": 985, "type": "edge", "label": "nextMoniker", "outV": 12, "inV": 987 }
"#;
let entry = Entry::new(
Id::Number(985),
Edge::NextMoniker(E11 {
out_v: Id::Number(12),
in_v: Id::Number(987),
}),
);
assert_serde(text, entry);
}
#[test]
fn package_information_vertex() {
let text = r#"{ "id": 991, "type": "vertex", "label": "packageInformation", "name": "mobx", "manager": "npm", "version": "5.6.0", "repository": { "type": "git", "url": "git+https://github.com/mobxjs/mobx.git" } }"#;
let entry = Entry::new(
Id::Number(991),
vertex::PackageInformation {
name: "mobx".to_owned(),
manager: "npm".to_owned(),
uri: None,
contents: None,
version: Some("5.6.0".to_owned()),
repository: Some(Repository {
r#type: "git".to_owned(),
url: "git+https://github.com/mobxjs/mobx.git".to_owned(),
commit_id: None,
}),
},
);
assert_serde(text, entry);
}
#[test]
fn package_information_edge() {
let text = r#"{ "id": 983, "type": "edge", "label": "packageInformation", "outV": 984, "inV": 991 }"#;
let entry = Entry::new(
Id::Number(983),
Edge::PackageInformation(E11 {
out_v: Id::Number(984),
in_v: Id::Number(991),
}),
);
assert_serde(text, entry);
}
#[test]
fn range() {
let text = r#"{ "id": 4, "type": "vertex", "label": "range", "start": { "line": 0, "character": 9 }, "end": { "line": 0, "character": 12 } }"#;
let entry = Entry::new(
Id::Number(4),
vertex::Range {
range: lsp::Range {
start: lsp::Position {
line: 0,
character: 9,
},
end: lsp::Position {
line: 0,
character: 12,
},
},
tag: None,
},
);
assert_serde(text, entry);
}
#[test]
fn range_tagged() {
let text = r#"{ "id": 7, "type": "vertex", "label": "range",
"start": { "line": 0, "character": 9 }, "end": { "line": 0, "character": 14 },
"tag": { "type": "definition", "text": "hello", "kind": 12, "fullRange": { "start": { "line": 0, "character": 0 }, "end": { "line": 1, "character": 1 } } }
}"#;
let entry = Entry::new(
Id::Number(7),
vertex::Range {
range: lsp::Range {
start: lsp::Position {
line: 0,
character: 9,
},
end: lsp::Position {
line: 0,
character: 14,
},
},
tag: Some(RangeTag::Definition(DefinitionTag {
text: "hello".to_owned(),
kind: lsp::SymbolKind::Function,
deprecated: None,
full_range: lsp::Range {
start: lsp::Position {
line: 0,
character: 0,
},
end: lsp::Position {
line: 1,
character: 1,
},
},
detail: None,
})),
},
);
assert_serde(text, entry);
}
#[test]
fn result_set() {
let text = r#"{ "id": 2, "type": "vertex", "label": "resultSet" }"#;
let entry = Entry::new(Id::Number(2), Vertex::ResultSet);
assert_serde(text, entry);
}
#[test]
fn contains() {
let text = r#"{ "id": 5, "type": "edge", "label": "contains", "outV": 1, "inVs": [4] }"#;
let entry = Entry::new(
Id::Number(5),
Edge::Contains(E1N {
out_v: Id::Number(1),
in_vs: vec![Id::Number(4)],
}),
);
assert_serde(text, entry);
}
#[test]
fn next() {
let text = r#"{ "id": 5, "type": "edge", "label": "next", "outV": 3, "inV": 2 }"#;
let entry = Entry::new(
Id::Number(5),
Edge::Next(E11 {
out_v: Id::Number(3),
in_v: Id::Number(2),
}),
);
assert_serde(text, entry);
}
#[test]
fn item() {
let text = r#"{ "id": 24, "type": "edge", "label": "item", "outV": 22, "inVs": [9], "document": 4 }"#;
let entry = Entry::new(
Id::Number(24),
edge::Item {
out_v: Id::Number(22),
in_vs: vec![Id::Number(9)],
document: Id::Number(4),
property: None,
},
);
assert_serde(text, entry);
}
#[test]
fn item_property() {
let text = r#"{ "id": 90, "type": "edge", "label": "item", "outV": 30, "inVs": [16,34,50], "document": 4, "property": "definitions" }"#;
let entry = Entry::new(
Id::Number(90),
edge::Item {
out_v: Id::Number(30),
in_vs: vec![Id::Number(16), Id::Number(34), Id::Number(50)],
document: Id::Number(4),
property: Some(ItemProperty::Definitions),
},
);
assert_serde(text, entry);
}
#[test]
fn definition_result() {
let text = r#"{ "id": 22, "type": "vertex", "label": "definitionResult" }"#;
let entry = Entry::new(Id::Number(22), Vertex::DefinitionResult);
assert_serde(text, entry);
}
#[test]
fn definition() {
let text = r#"{ "id": 23, "type": "edge", "label": "textDocument/definition", "outV": 6, "inV": 22 }"#;
let entry = Entry::new(
Id::Number(23),
Edge::Definition(E11 {
out_v: Id::Number(6),
in_v: Id::Number(22),
}),
);
assert_serde(text, entry);
}
#[test]
fn hover_result() {
let text = r#"{ "id": 6, "type": "vertex", "label": "hoverResult", "result": { "contents": [ { "language": "typescript", "value": "function bar(): void" } ], "range": { "start": { "line": 4, "character": 2 }, "end": { "line": 4, "character": 5 } } } }"#;
let entry = Entry::new(
Id::Number(6),
Vertex::HoverResult {
result: lsp::Hover {
contents: HoverContents::Array(vec![MarkedString::LanguageString(
LanguageString {
language: "typescript".to_owned(),
value: "function bar(): void".to_owned(),
},
)]),
range: Some(lsp::Range {
start: Position {
line: 4,
character: 2,
},
end: Position {
line: 4,
character: 5,
},
}),
},
},
);
assert_serde(text, entry);
}
#[test]
fn hover() {
let text =
r#"{ "id": 7, "type": "edge", "label": "textDocument/hover", "outV": 4, "inV": 6 }"#;
let entry = Entry::new(
Id::Number(7),
Edge::Hover(E11 {
out_v: Id::Number(4),
in_v: Id::Number(6),
}),
);
assert_serde(text, entry);
}
#[test]
fn reference_result() {
let text = r#"{ "id": 25, "type": "vertex", "label": "referenceResult" }"#;
let entry = Entry::new(Id::Number(25), Vertex::ReferenceResult);
assert_serde(text, entry);
}
#[test]
fn references() {
let text = r#"{ "id": 26, "type": "edge", "label": "textDocument/references", "outV": 6, "inV": 25 }"#;
let entry = Entry::new(
Id::Number(26),
Edge::References(E11 {
out_v: Id::Number(6),
in_v: Id::Number(25),
}),
);
assert_serde(text, entry);
}
#[test]
fn type_definition_result() {
let text = r#"{ "id" : 37, "type": "vertex", "label": "typeDefinitionResult" }"#;
let entry = Entry::new(Id::Number(37), Vertex::TypeDefinitionResult);
assert_serde(text, entry);
}
#[test]
fn type_definition() {
let text = r#"{ "id": 38, "type": "edge", "label": "textDocument/typeDefinition", "outV": 26, "inV": 37 }"#;
let entry = Entry::new(
Id::Number(38),
Edge::TypeDefinition(E11 {
out_v: Id::Number(26),
in_v: Id::Number(37),
}),
);
assert_serde(text, entry);
}
#[test]
fn folding_range_result() {
let text = r#"{ "id": 112, "type": "vertex", "label": "foldingRangeResult", "result": [
{ "startLine": 0, "startCharacter": 16, "endLine": 2, "endCharacter": 1 },
{ "startLine": 4, "startCharacter": 16, "endLine": 6, "endCharacter": 1 },
{ "startLine": 8, "startCharacter": 16, "endLine": 10, "endCharacter": 1 }
]}"#;
let entry = Entry::new(
Id::Number(112),
Vertex::FoldingRangeResult {
result: vec![
lsp::FoldingRange {
start_line: 0,
start_character: Some(16),
end_line: 2,
end_character: Some(1),
kind: None,
},
lsp::FoldingRange {
start_line: 4,
start_character: Some(16),
end_line: 6,
end_character: Some(1),
kind: None,
},
lsp::FoldingRange {
start_line: 8,
start_character: Some(16),
end_line: 10,
end_character: Some(1),
kind: None,
},
],
},
);
assert_serde(text, entry);
}
#[test]
fn folding_range() {
let text = r#"{ "id": 113, "type": "edge", "label": "textDocument/foldingRange", "outV": 2, "inV": 112 }"#;
let entry = Entry::new(
Id::Number(113),
Edge::FoldingRange(E11 {
out_v: Id::Number(2),
in_v: Id::Number(112),
}),
);
assert_serde(text, entry);
}
#[test]
fn document_symbol_result() {
let text = r#"{ "id": 39, "type": "vertex", "label": "documentSymbolResult", "result": [ { "id": 7, "children": [ { "id": 18 }, { "id": 29 } ] } ] }"#;
let entry = Entry::new(
Id::Number(39),
Vertex::DocumentSymbolResult {
result: DocumentSymbolResult::RangeBasedDocumentSymbols(vec![
RangeBasedDocumentSymbol {
id: Id::Number(7),
children: Some(vec![
RangeBasedDocumentSymbol {
id: Id::Number(18),
children: None,
},
RangeBasedDocumentSymbol {
id: Id::Number(29),
children: None,
},
]),
},
]),
},
);
assert_serde(text, entry);
}
#[test]
fn document_symbol() {
let text = r#"{ "id": 40, "type": "edge", "label": "textDocument/documentSymbol", "outV": 2, "inV": 39 }"#;
let entry = Entry::new(
Id::Number(40),
Edge::DocumentSymbol(E11 {
out_v: Id::Number(2),
in_v: Id::Number(39),
}),
);
assert_serde(text, entry);
}
#[test]
fn diagnostic_result() {
let text = r#"{ "id": 18, "type": "vertex", "label": "diagnosticResult", "result": [ { "severity": 1, "code": 2322, "message": "Type '10' is not assignable to type 'string'.", "range": { "start": { "line": 1, "character": 5 }, "end": { "line": 1, "character": 6 } } } ] }"#;
let entry = Entry::new(
Id::Number(18),
Vertex::DiagnosticResult {
result: vec![lsp::Diagnostic {
range: lsp::Range {
start: lsp::Position {
line: 1,
character: 5,
},
end: lsp::Position {
line: 1,
character: 6,
},
},
severity: Some(lsp::DiagnosticSeverity::Error),
code: Some(Id::Number(2322)),
code_description: None,
source: None,
message: "Type '10' is not assignable to type 'string'.".to_owned(),
related_information: None,
tags: None,
data: None,
}],
},
);
assert_serde(text, entry);
}
#[test]
fn diagnostic() {
let text = r#"{ "id": 19, "type": "edge", "label": "textDocument/diagnostic", "outV": 2, "inV": 18 }"#;
let entry = Entry::new(
Id::Number(19),
Edge::Diagnostic(E11 {
out_v: Id::Number(2),
in_v: Id::Number(18),
}),
);
assert_serde(text, entry);
}
}