use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Document {
pub schema: String,
pub metadata: Metadata,
pub entities: Vec<Entity>,
pub symbols: Vec<SymbolEntry>,
#[serde(
rename = "unresolvedReferences",
skip_serializing_if = "Vec::is_empty",
default
)]
pub unresolved_references: Vec<UnresolvedReference>,
}
impl Document {
pub fn new(metadata: Metadata) -> Self {
Self {
schema: crate::SCHEMA_VERSION.to_string(),
metadata,
entities: Vec::new(),
symbols: Vec::new(),
unresolved_references: Vec::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metadata {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
pub language: Language,
#[serde(rename = "generatedAt")]
pub generated_at: String,
#[serde(rename = "sourceRoot", skip_serializing_if = "Option::is_none")]
pub source_root: Option<String>,
#[serde(rename = "idPrefix", skip_serializing_if = "Option::is_none")]
pub id_prefix: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub files: Vec<String>,
#[serde(
rename = "externalLinks",
skip_serializing_if = "HashMap::is_empty",
default
)]
pub external_links: HashMap<String, ExternalLinkMapping>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Language {
Ruby,
TypeScript,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ExternalLinkMapping {
#[serde(rename = "baseUrl", skip_serializing_if = "Option::is_none")]
pub base_url: Option<String>,
#[serde(rename = "urlTemplate", skip_serializing_if = "Option::is_none")]
pub url_template: Option<String>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub symbols: HashMap<String, String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub transform: Option<TransformRules>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TransformRules {
#[serde(rename = "nameSeparator", skip_serializing_if = "Option::is_none")]
pub name_separator: Option<String>,
#[serde(rename = "methodPrefix", skip_serializing_if = "Option::is_none")]
pub method_prefix: Option<String>,
#[serde(rename = "classMethodPrefix", skip_serializing_if = "Option::is_none")]
pub class_method_prefix: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lowercase: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolEntry {
pub id: String,
pub name: String,
#[serde(rename = "qualifiedName")]
pub qualified_name: String,
pub kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub signature: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnresolvedReference {
pub name: String,
#[serde(rename = "qualifiedName", skip_serializing_if = "Option::is_none")]
pub qualified_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub package: Option<String>,
#[serde(rename = "referencedFrom")]
pub referenced_from: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind")]
pub enum Entity {
#[serde(rename = "module")]
Module(Module),
#[serde(rename = "class")]
Class(Class),
#[serde(rename = "interface")]
Interface(Interface),
#[serde(rename = "type")]
TypeAlias(TypeAlias),
#[serde(rename = "enum")]
Enum(Enum),
#[serde(rename = "method")]
Method(Callable),
#[serde(rename = "function")]
Function(Callable),
#[serde(rename = "constructor")]
Constructor(Callable),
#[serde(rename = "property")]
Property(Property),
#[serde(rename = "constant")]
Constant(Constant),
}
impl Entity {
pub fn id(&self) -> &str {
match self {
Entity::Module(m) => &m.base.id,
Entity::Class(c) => &c.base.id,
Entity::Interface(i) => &i.base.id,
Entity::TypeAlias(t) => &t.base.id,
Entity::Enum(e) => &e.base.id,
Entity::Method(c) | Entity::Function(c) | Entity::Constructor(c) => &c.base.id,
Entity::Property(p) => &p.base.id,
Entity::Constant(c) => &c.base.id,
}
}
pub fn name(&self) -> &str {
match self {
Entity::Module(m) => &m.base.name,
Entity::Class(c) => &c.base.name,
Entity::Interface(i) => &i.base.name,
Entity::TypeAlias(t) => &t.base.name,
Entity::Enum(e) => &e.base.name,
Entity::Method(c) | Entity::Function(c) | Entity::Constructor(c) => &c.base.name,
Entity::Property(p) => &p.base.name,
Entity::Constant(c) => &c.base.name,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct BaseEntity {
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub location: Option<SourceLocation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub docs: Option<Documentation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<Visibility>,
#[serde(rename = "isPrivateApi", skip_serializing_if = "Option::is_none")]
pub is_private_api: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SourceLocation {
pub file: String,
pub line: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub column: Option<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Visibility {
Public,
Protected,
Private,
Internal,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Documentation {
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub examples: Vec<Example>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub see: Vec<SeeReference>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub notes: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub todos: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deprecated: Option<Deprecation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub since: Option<String>,
#[serde(skip_serializing_if = "HashMap::is_empty", default)]
pub tags: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Example {
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
pub code: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SeeReference {
pub text: String,
#[serde(rename = "ref", skip_serializing_if = "Option::is_none")]
pub reference: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Deprecation {
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub since: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub replacement: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeReference {
pub name: String,
pub kind: TypeKind,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub args: Vec<TypeReference>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub members: Vec<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nullable: Option<bool>,
#[serde(rename = "ref", skip_serializing_if = "Option::is_none")]
pub reference: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub package: Option<String>,
#[serde(rename = "qualifiedName", skip_serializing_if = "Option::is_none")]
pub qualified_name: Option<String>,
}
impl TypeReference {
pub fn simple(name: impl Into<String>) -> Self {
Self {
name: name.into(),
kind: TypeKind::Simple,
args: Vec::new(),
members: Vec::new(),
value: None,
nullable: None,
reference: None,
package: None,
qualified_name: None,
}
}
pub fn void() -> Self {
Self::simple("void")
}
pub fn union(members: Vec<TypeReference>) -> Self {
Self {
name: String::new(),
kind: TypeKind::Union,
args: Vec::new(),
members,
value: None,
nullable: None,
reference: None,
package: None,
qualified_name: None,
}
}
pub fn generic(name: impl Into<String>, args: Vec<TypeReference>) -> Self {
Self {
name: name.into(),
kind: TypeKind::Generic,
args,
members: Vec::new(),
value: None,
nullable: None,
reference: None,
package: None,
qualified_name: None,
}
}
pub fn nullable(mut self) -> Self {
self.nullable = Some(true);
self
}
pub fn with_ref(mut self, reference: impl Into<String>) -> Self {
self.reference = Some(reference.into());
self
}
pub fn external(
mut self,
package: impl Into<String>,
qualified_name: impl Into<String>,
) -> Self {
self.package = Some(package.into());
self.qualified_name = Some(qualified_name.into());
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TypeKind {
Simple,
Generic,
Union,
Intersection,
Array,
Tuple,
Literal,
Function,
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Parameter {
pub name: String,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub param_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub optional: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rest: Option<bool>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub options: Vec<OptionEntry>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OptionEntry {
pub name: String,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub option_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Throws {
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub throw_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct YieldBlock {
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub params: Vec<Parameter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub returns: Option<TypeReference>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeParameter {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub constraint: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Module {
#[serde(flatten)]
pub base: BaseEntity,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub extends: Vec<TypeReference>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub includes: Vec<TypeReference>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub functions: Vec<Callable>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub properties: Vec<Property>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub constants: Vec<Constant>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub classes: Vec<Class>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub modules: Vec<Module>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub interfaces: Vec<Interface>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub types: Vec<TypeAlias>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub enums: Vec<Enum>,
#[serde(rename = "isConcern", skip_serializing_if = "Option::is_none")]
pub is_concern: Option<bool>,
#[serde(
rename = "instanceMethods",
skip_serializing_if = "Vec::is_empty",
default
)]
pub instance_methods: Vec<Callable>,
#[serde(
rename = "classMethods",
skip_serializing_if = "Vec::is_empty",
default
)]
pub class_methods: Vec<Callable>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Class {
#[serde(flatten)]
pub base: BaseEntity,
#[serde(skip_serializing_if = "Option::is_none")]
pub extends: Option<TypeReference>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub implements: Vec<TypeReference>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub includes: Vec<TypeReference>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub prepends: Vec<TypeReference>,
#[serde(rename = "typeParams", skip_serializing_if = "Vec::is_empty", default)]
pub type_params: Vec<TypeParameter>,
#[serde(rename = "abstract", skip_serializing_if = "Option::is_none")]
pub is_abstract: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub constructor: Option<Box<Callable>>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub properties: Vec<Property>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub methods: Vec<Callable>,
#[serde(
rename = "staticProperties",
skip_serializing_if = "Vec::is_empty",
default
)]
pub static_properties: Vec<Property>,
#[serde(
rename = "staticMethods",
skip_serializing_if = "Vec::is_empty",
default
)]
pub static_methods: Vec<Callable>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub constants: Vec<Constant>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub nested: Vec<Entity>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Interface {
#[serde(flatten)]
pub base: BaseEntity,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub extends: Vec<TypeReference>,
#[serde(rename = "typeParams", skip_serializing_if = "Vec::is_empty", default)]
pub type_params: Vec<TypeParameter>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub properties: Vec<Property>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub methods: Vec<Callable>,
#[serde(
rename = "callSignatures",
skip_serializing_if = "Vec::is_empty",
default
)]
pub call_signatures: Vec<Callable>,
#[serde(
rename = "indexSignatures",
skip_serializing_if = "Vec::is_empty",
default
)]
pub index_signatures: Vec<IndexSignature>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IndexSignature {
#[serde(rename = "keyType", skip_serializing_if = "Option::is_none")]
pub key_type: Option<TypeReference>,
#[serde(rename = "valueType", skip_serializing_if = "Option::is_none")]
pub value_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub readonly: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeAlias {
#[serde(flatten)]
pub base: BaseEntity,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub aliased_type: Option<TypeReference>,
#[serde(rename = "typeParams", skip_serializing_if = "Vec::is_empty", default)]
pub type_params: Vec<TypeParameter>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Enum {
#[serde(flatten)]
pub base: BaseEntity,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub members: Vec<EnumMember>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnumMember {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub docs: Option<Documentation>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Callable {
#[serde(flatten)]
pub base: BaseEntity,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub params: Vec<Parameter>,
#[serde(skip_serializing_if = "Option::is_none")]
pub returns: Option<TypeReference>,
#[serde(rename = "returnsDescription", skip_serializing_if = "Option::is_none")]
pub returns_description: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub throws: Vec<Throws>,
#[serde(skip_serializing_if = "Option::is_none")]
pub yields: Option<YieldBlock>,
#[serde(rename = "async", skip_serializing_if = "Option::is_none")]
pub is_async: Option<bool>,
#[serde(rename = "static", skip_serializing_if = "Option::is_none")]
pub is_static: Option<bool>,
#[serde(rename = "abstract", skip_serializing_if = "Option::is_none")]
pub is_abstract: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub generator: Option<bool>,
#[serde(rename = "typeParams", skip_serializing_if = "Vec::is_empty", default)]
pub type_params: Vec<TypeParameter>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub overloads: Vec<Callable>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Property {
#[serde(flatten)]
pub base: BaseEntity,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub prop_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub readonly: Option<bool>,
#[serde(rename = "static", skip_serializing_if = "Option::is_none")]
pub is_static: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub optional: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub getter: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub setter: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Constant {
#[serde(flatten)]
pub base: BaseEntity,
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
pub const_type: Option<TypeReference>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
}