diff --git a/crates/aiken-lang/src/tipo/infer.rs b/crates/aiken-lang/src/tipo/infer.rs index 87028290..932260e7 100644 --- a/crates/aiken-lang/src/tipo/infer.rs +++ b/crates/aiken-lang/src/tipo/infer.rs @@ -80,7 +80,6 @@ impl UntypedModule { for def in consts.into_iter().chain(not_consts) { let definition = infer_definition(def, &name, &mut hydrators, &mut environment, kind)?; - definitions.push(definition); } @@ -339,6 +338,7 @@ fn infer_definition( label, annotation, location, + doc, .. }, t, @@ -348,7 +348,7 @@ fn infer_definition( annotation, location, tipo: t.clone(), - doc: None, + doc, } }, ) diff --git a/crates/aiken-project/src/blueprint/mod.rs b/crates/aiken-project/src/blueprint/mod.rs index 298e4741..faccec00 100644 --- a/crates/aiken-project/src/blueprint/mod.rs +++ b/crates/aiken-project/src/blueprint/mod.rs @@ -5,7 +5,7 @@ pub mod validator; use crate::{config::Config, module::CheckedModules}; use aiken_lang::uplc::CodeGenerator; use error::*; -use schema::Schema; +use schema::NamedSchema; use std::fmt::Debug; use validator::{Purpose, Validator}; @@ -38,11 +38,15 @@ impl Blueprint { purpose, datum: datum .map(|datum| { - Schema::from_type(modules.into(), &datum.arg_name.get_label(), &datum.tipo) - .map_err(Error::Schema) + NamedSchema::from_type( + modules.into(), + &datum.arg_name.get_label(), + &datum.tipo, + ) + .map_err(Error::Schema) }) .transpose()?, - redeemer: Schema::from_type( + redeemer: NamedSchema::from_type( modules.into(), &redeemer.arg_name.get_label(), &redeemer.tipo, diff --git a/crates/aiken-project/src/blueprint/schema.rs b/crates/aiken-project/src/blueprint/schema.rs index 54a3578f..f9e7898b 100644 --- a/crates/aiken-project/src/blueprint/schema.rs +++ b/crates/aiken-project/src/blueprint/schema.rs @@ -4,7 +4,10 @@ use aiken_lang::{ tipo::Type, }; use miette::Diagnostic; -use serde::ser::{Serialize, SerializeStruct, Serializer}; +use serde::{ + self, + ser::{Serialize, SerializeStruct, Serializer}, +}; use serde_json; use std::{ collections::HashMap, @@ -12,6 +15,15 @@ use std::{ sync::Arc, }; +#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize)] +pub struct NamedSchema { + pub title: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + #[serde(flatten)] + pub schema: Schema, +} + #[derive(Debug, PartialEq, Eq, Clone)] pub enum Schema { Integer, @@ -24,10 +36,10 @@ pub enum Schema { #[derive(Debug, PartialEq, Eq, Clone)] pub struct Constructor { pub index: usize, - pub fields: Vec, + pub fields: Vec, } -impl Schema { +impl NamedSchema { pub fn from_type( modules: &HashMap, name: &str, @@ -39,8 +51,16 @@ impl Schema { name: type_name, .. } if module_name.is_empty() => match &type_name[..] { - "ByteArray" => Ok(Schema::Bytes), - "Integer" => Ok(Schema::Integer), + "ByteArray" => Ok(NamedSchema { + title: name.to_string(), + description: None, + schema: Schema::Bytes, + }), + "Integer" => Ok(NamedSchema { + title: name.to_string(), + description: None, + schema: Schema::Bytes, + }), _ => Err(Error::UnsupportedPrimitiveType { type_name: type_name.clone(), }), @@ -52,7 +72,12 @@ impl Schema { } => { let module = modules.get(module_name).unwrap(); let constructor = find_definition(type_name, &module.ast.definitions).unwrap(); - Self::from_data_type(modules, constructor) + let schema = Schema::from_data_type(modules, constructor)?; + Ok(NamedSchema { + title: constructor.name.clone(), + description: constructor.doc.clone().map(|s| s.trim().to_string()), + schema, + }) } Type::Fn { .. } | Type::Var { .. } | Type::Tuple { .. } => { Err(Error::UnsupportedKind { @@ -62,7 +87,9 @@ impl Schema { } } } +} +impl Schema { pub fn from_data_type( modules: &HashMap, data_type: &DataType>, @@ -71,11 +98,13 @@ impl Schema { for (index, constructor) in data_type.constructors.iter().enumerate() { let mut fields = vec![]; for field in constructor.arguments.iter() { - fields.push(Schema::from_type( + let mut schema = NamedSchema::from_type( modules, &field.label.clone().unwrap_or_default(), &field.tipo, - )?); + )?; + schema.description = field.doc.clone().map(|s| s.trim().to_string()); + fields.push(schema); } variants.push(Constructor { index, fields }); } @@ -187,7 +216,7 @@ pub mod test { use super::*; use serde_json::{self, json, Value}; - pub fn assert_json(schema: &Schema, expected: Value) { + pub fn assert_json(schema: &impl Serialize, expected: Value) { assert_eq!(serde_json::to_value(schema).unwrap(), expected); } @@ -350,4 +379,37 @@ pub mod test { }), ) } + + #[test] + fn serialize_named_no_description() { + let schema = NamedSchema { + title: "foo".to_string(), + description: None, + schema: Schema::Integer, + }; + assert_json( + &schema, + json!({ + "title": "foo", + "dataType": "integer" + }), + ) + } + + #[test] + fn serialize_named_description() { + let schema = NamedSchema { + title: "foo".to_string(), + description: Some("Lorem Ipsum".to_string()), + schema: Schema::Integer, + }; + assert_json( + &schema, + json!({ + "title": "foo", + "description": "Lorem Ipsum", + "dataType": "integer" + }), + ) + } } diff --git a/crates/aiken-project/src/blueprint/validator.rs b/crates/aiken-project/src/blueprint/validator.rs index 7166df4b..059eebdb 100644 --- a/crates/aiken-project/src/blueprint/validator.rs +++ b/crates/aiken-project/src/blueprint/validator.rs @@ -1,4 +1,4 @@ -use super::schema::Schema; +use super::schema::NamedSchema; use pallas::ledger::primitives::babbage as cardano; use pallas_traverse::ComputeHash; use serde::{ @@ -13,8 +13,8 @@ pub struct Validator { pub title: String, pub purpose: Purpose, pub description: Option, - pub datum: Option, - pub redeemer: Schema, + pub datum: Option, + pub redeemer: NamedSchema, pub program: Program, } @@ -82,7 +82,7 @@ impl Display for Purpose { #[cfg(test)] mod test { - use super::super::schema::Constructor; + use super::super::schema::{Constructor, Schema}; use super::*; use serde_json::{self, json}; use uplc::parser; @@ -98,10 +98,14 @@ mod test { description: Some("Lorem ipsum".to_string()), purpose: Purpose::Spend, datum: None, - redeemer: Schema::AnyOf(vec![Constructor { - index: 0, - fields: vec![Schema::Bytes], - }]), + redeemer: NamedSchema { + title: "Bar".to_string(), + description: None, + schema: Schema::AnyOf(vec![Constructor { + index: 0, + fields: vec![Schema::Bytes], + }]), + }, program, }; assert_eq!( @@ -111,6 +115,7 @@ mod test { "description": "Lorem ipsum", "purpose": "spend", "redeemer": { + "title": "Bar", "dataType": "constructor", "index": 0, "fields": [{ diff --git a/crates/aiken-project/src/lib.rs b/crates/aiken-project/src/lib.rs index 5bdd3411..2741322b 100644 --- a/crates/aiken-project/src/lib.rs +++ b/crates/aiken-project/src/lib.rs @@ -135,11 +135,7 @@ where let destination = destination.unwrap_or_else(|| self.root.join("docs")); - let mut parsed_modules = self.parse_sources(self.config.name.clone())?; - - for (_, module) in parsed_modules.iter_mut() { - module.attach_doc_and_module_comments(); - } + let parsed_modules = self.parse_sources(self.config.name.clone())?; self.type_check(parsed_modules)?; @@ -349,7 +345,7 @@ where // Store the name ast.name = name.clone(); - let module = ParsedModule { + let mut module = ParsedModule { kind, ast, code, @@ -370,6 +366,8 @@ where }); } + module.attach_doc_and_module_comments(); + parsed_modules.insert(module.name.clone(), module); } Err(errs) => {