use super::RegistryBase;
use crate::template::{Catalog, PresetInfo, PrimitivesManifest, Theme};
use crate::theme::ThemeRegistry;
use anyhow::Context;
use handlebars::Handlebars;
use serde_json::Value;
use std::collections::BTreeMap;
const BUILT_IN_BUNDLE: &str = include_str!(concat!(env!("OUT_DIR"), "/embedded_templates.json"));
pub fn load_builtin() -> anyhow::Result<RegistryBase> {
let bundle: Value =
serde_json::from_str(BUILT_IN_BUNDLE).context("parsing embedded templates bundle")?;
let mut handlebars = Handlebars::new();
handlebars.set_strict_mode(false);
crate::render::helpers::register_all(&mut handlebars);
register_primitives(&mut handlebars, &bundle)?;
let presets = load_presets(&mut handlebars, &bundle)?;
let themes = load_themes(&bundle)?;
let primitives_manifest = load_primitives_manifest(&bundle)?;
let categories = load_catalog(&bundle)?;
Ok(RegistryBase {
handlebars,
presets,
themes,
primitives_manifest,
categories,
})
}
fn register_primitives(hbs: &mut Handlebars<'static>, bundle: &Value) -> anyhow::Result<()> {
let primitives = bundle
.get("primitives")
.and_then(|v| v.as_object())
.context("bundle missing 'primitives' object")?;
for (name, source_val) in primitives {
let source = source_val
.as_str()
.context("primitive source must be string")?;
hbs.register_partial(name, source)
.with_context(|| format!("registering primitive partial '{}'", name))?;
}
Ok(())
}
fn load_presets(
hbs: &mut Handlebars<'static>,
bundle: &Value,
) -> anyhow::Result<BTreeMap<String, PresetInfo>> {
let presets = bundle
.get("presets")
.and_then(|v| v.as_object())
.context("bundle missing 'presets' object")?;
let mut map = BTreeMap::new();
for (name, preset_data) in presets {
let source = preset_data["source"]
.as_str()
.context("preset source missing")?;
let schema = preset_data["schema"].clone();
hbs.register_template_string(name, source)
.with_context(|| format!("registering preset template '{}'", name))?;
let info = PresetInfo {
name: name.clone(),
category: schema["x-category"].as_str().unwrap_or("").to_string(),
title: schema["title"].as_str().unwrap_or(name).to_string(),
description: schema["description"].as_str().unwrap_or("").to_string(),
tags: schema["x-tags"]
.as_array()
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(String::from))
.collect()
})
.unwrap_or_default(),
use_cases: schema["x-use-cases"]
.as_array()
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(String::from))
.collect()
})
.unwrap_or_default(),
example: schema.get("x-example").cloned().unwrap_or(Value::Null),
schema,
template_source: source.to_string(),
};
map.insert(name.clone(), info);
}
Ok(map)
}
fn load_themes(bundle: &Value) -> anyhow::Result<ThemeRegistry> {
let themes_obj = bundle
.get("themes")
.and_then(|v| v.as_object())
.context("bundle missing 'themes' object")?;
let mut registry = ThemeRegistry::new();
for (name, theme_json) in themes_obj {
let theme: Theme = serde_json::from_value(theme_json.clone())
.with_context(|| format!("parsing theme '{}'", name))?;
registry.insert(theme);
}
Ok(registry)
}
fn load_primitives_manifest(bundle: &Value) -> anyhow::Result<PrimitivesManifest> {
let manifest_json = bundle
.get("primitives_manifest")
.cloned()
.context("bundle missing 'primitives_manifest'")?;
serde_json::from_value(manifest_json).context("parsing primitives manifest")
}
fn load_catalog(bundle: &Value) -> anyhow::Result<Vec<crate::template::Category>> {
let catalog_json = bundle
.get("catalog")
.cloned()
.context("bundle missing 'catalog'")?;
let catalog: Catalog = serde_json::from_value(catalog_json).context("parsing catalog")?;
Ok(catalog.categories)
}