type_bridge_schema_codegen/
lib.rs1use std::collections::BTreeMap;
4
5mod package;
6mod python;
7mod rust;
8mod typescript;
9
10pub use package::GeneratedPackage;
11pub use python::PythonEmitter;
12pub use rust::RustEmitter;
13pub use typescript::TypeScriptEmitter;
14
15use type_bridge_contract::diagnostic::{Diagnostic, DiagnosticCategory, DiagnosticCode};
16use type_bridge_contract::projection::{ModelProjection, ProjectedAnnotation};
17use type_bridge_contract::schema::{AnnotationFactId, AnnotationKindId, SchemaAnnotationValue};
18
19fn invalid(code: &'static str, message: impl Into<String>) -> Diagnostic {
20 Diagnostic::new(
21 DiagnosticCategory::InvalidContract,
22 DiagnosticCode::new(code).expect("schema-codegen diagnostic code is valid"),
23 message,
24 )
25}
26
27fn model_documentation(model: &ModelProjection) -> Option<String> {
28 let type_doc = documentation_annotation(model.declaration().annotations());
29 let direct_sub_doc = model
30 .declaration()
31 .direct_sub()
32 .and_then(|sub| documentation_annotation(sub.annotations()).map(|doc| (sub, doc)));
33
34 match (type_doc, direct_sub_doc) {
35 (None, None) => None,
36 (Some(type_doc), None) => Some(type_doc.to_owned()),
37 (type_doc, Some((sub, sub_doc))) => {
38 let edge_doc = format!(
39 "Direct subtype of `{}`:\n{sub_doc}",
40 sub.id().supertype().label()
41 );
42 Some(match type_doc {
43 Some(type_doc) => format!("{type_doc}\n\n{edge_doc}"),
44 None => edge_doc,
45 })
46 }
47 }
48}
49
50fn documentation_annotation(
51 annotations: &BTreeMap<AnnotationFactId, ProjectedAnnotation>,
52) -> Option<&str> {
53 annotations.values().find_map(|annotation| {
54 if annotation.id().kind() != &AnnotationKindId::Doc {
55 return None;
56 }
57 match annotation.value() {
58 SchemaAnnotationValue::Doc(doc) => Some(doc.as_str()),
59 _ => None,
60 }
61 })
62}