hmd-profile-general 0.1.0-alpha.8

Official general profile validation and schema support for Human Markdown
Documentation
use hmd_core::{BlockDescriptor, MetadataField, MetadataFieldKind, ProfileDescriptor};
use schemars::{schema_for, JsonSchema};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CalloutMeta {
    pub id: Option<String>,
    #[serde(rename = "type")]
    pub type_: Option<String>,
    pub title: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct AsideMeta {
    pub id: Option<String>,
    pub title: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct DetailsMeta {
    pub id: Option<String>,
    pub summary: Option<String>,
    pub open: Option<bool>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct FigureMeta {
    pub id: Option<String>,
    pub src: String,
    pub alt: String,
    pub caption: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CardsMeta {
    pub id: Option<String>,
    pub title: Option<String>,
    pub columns: Option<u64>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CardMeta {
    pub id: Option<String>,
    pub title: String,
    pub href: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct TabsMeta {
    pub id: Option<String>,
    pub title: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct TabMeta {
    pub id: Option<String>,
    pub label: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct MetricMeta {
    pub id: Option<String>,
    pub label: String,
    pub value: serde_json::Value,
    pub unit: Option<String>,
    pub trend: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct TimelineMeta {
    pub id: Option<String>,
    pub title: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct EventMeta {
    pub id: Option<String>,
    pub at: Option<String>,
    pub title: Option<String>,
    pub kind: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct GeneralProfileSchema {
    pub callout: Option<CalloutMeta>,
    pub aside: Option<AsideMeta>,
    pub details: Option<DetailsMeta>,
    pub figure: Option<FigureMeta>,
    pub cards: Option<CardsMeta>,
    pub card: Option<CardMeta>,
    pub tabs: Option<TabsMeta>,
    pub tab: Option<TabMeta>,
    pub metric: Option<MetricMeta>,
    pub timeline: Option<TimelineMeta>,
    pub event: Option<EventMeta>,
}

const CALLOUT_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::optional("type", MetadataFieldKind::String),
    MetadataField::optional("title", MetadataFieldKind::String),
];
const ASIDE_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::optional("title", MetadataFieldKind::String),
];
const DETAILS_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::optional("summary", MetadataFieldKind::String),
    MetadataField::optional("open", MetadataFieldKind::Boolean),
];
const FIGURE_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::required("src", MetadataFieldKind::String),
    MetadataField::required("alt", MetadataFieldKind::String),
    MetadataField::optional("caption", MetadataFieldKind::String),
];
const CARDS_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::optional("title", MetadataFieldKind::String),
    MetadataField::optional("columns", MetadataFieldKind::Number),
];
const CARD_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::required("title", MetadataFieldKind::String),
    MetadataField::optional("href", MetadataFieldKind::String),
];
const TABS_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::optional("title", MetadataFieldKind::String),
];
const TAB_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::required("label", MetadataFieldKind::String),
];
const METRIC_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::required("label", MetadataFieldKind::String),
    MetadataField::required("value", MetadataFieldKind::Any),
    MetadataField::optional("unit", MetadataFieldKind::String),
    MetadataField::optional("trend", MetadataFieldKind::String),
];
const TIMELINE_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::optional("title", MetadataFieldKind::String),
];
const EVENT_FIELDS: &[MetadataField] = &[
    MetadataField::optional("id", MetadataFieldKind::String),
    MetadataField::optional("at", MetadataFieldKind::String),
    MetadataField::optional("title", MetadataFieldKind::String),
    MetadataField::optional("kind", MetadataFieldKind::String),
];

const CARD_CHILDREN: &[&str] = &["card"];
const TAB_CHILDREN: &[&str] = &["tab"];
const EVENT_CHILDREN: &[&str] = &["event"];

const BLOCKS: &[BlockDescriptor] = &[
    BlockDescriptor {
        block_type: "callout",
        schema_id: "https://hmd.dev/schemas/general@0.1/callout.schema.json",
        fields: CALLOUT_FIELDS,
        allowed_child_block_types: None,
    },
    BlockDescriptor {
        block_type: "aside",
        schema_id: "https://hmd.dev/schemas/general@0.1/aside.schema.json",
        fields: ASIDE_FIELDS,
        allowed_child_block_types: None,
    },
    BlockDescriptor {
        block_type: "details",
        schema_id: "https://hmd.dev/schemas/general@0.1/details.schema.json",
        fields: DETAILS_FIELDS,
        allowed_child_block_types: None,
    },
    BlockDescriptor {
        block_type: "figure",
        schema_id: "https://hmd.dev/schemas/general@0.1/figure.schema.json",
        fields: FIGURE_FIELDS,
        allowed_child_block_types: None,
    },
    BlockDescriptor {
        block_type: "cards",
        schema_id: "https://hmd.dev/schemas/general@0.1/cards.schema.json",
        fields: CARDS_FIELDS,
        allowed_child_block_types: Some(CARD_CHILDREN),
    },
    BlockDescriptor {
        block_type: "card",
        schema_id: "https://hmd.dev/schemas/general@0.1/card.schema.json",
        fields: CARD_FIELDS,
        allowed_child_block_types: None,
    },
    BlockDescriptor {
        block_type: "tabs",
        schema_id: "https://hmd.dev/schemas/general@0.1/tabs.schema.json",
        fields: TABS_FIELDS,
        allowed_child_block_types: Some(TAB_CHILDREN),
    },
    BlockDescriptor {
        block_type: "tab",
        schema_id: "https://hmd.dev/schemas/general@0.1/tab.schema.json",
        fields: TAB_FIELDS,
        allowed_child_block_types: None,
    },
    BlockDescriptor {
        block_type: "metric",
        schema_id: "https://hmd.dev/schemas/general@0.1/metric.schema.json",
        fields: METRIC_FIELDS,
        allowed_child_block_types: None,
    },
    BlockDescriptor {
        block_type: "timeline",
        schema_id: "https://hmd.dev/schemas/general@0.1/timeline.schema.json",
        fields: TIMELINE_FIELDS,
        allowed_child_block_types: Some(EVENT_CHILDREN),
    },
    BlockDescriptor {
        block_type: "event",
        schema_id: "https://hmd.dev/schemas/general@0.1/event.schema.json",
        fields: EVENT_FIELDS,
        allowed_child_block_types: None,
    },
];

pub const PROFILE: ProfileDescriptor = ProfileDescriptor {
    id: "general@0.1",
    name: "general",
    version: "0.1",
    source: "official",
    blocks: BLOCKS,
    reference_rules: &[],
};

pub fn descriptor() -> ProfileDescriptor {
    PROFILE
}

pub fn register_profile() -> ProfileDescriptor {
    descriptor()
}

pub fn json_schema() -> serde_json::Value {
    serde_json::to_value(schema_for!(GeneralProfileSchema)).expect("serializes schema")
}