Skip to main content

ishou_render/
json.rs

1//! JSON renderer — emits W3C Design Tokens-style JSON so Figma / Style
2//! Dictionary / downstream tools can import.
3
4use ishou_tokens::TokenSet;
5use serde_json::{Map, Value, json};
6
7pub fn render(t: &TokenSet) -> String {
8    let mut root = Map::new();
9    // colors
10    let mut color = Map::new();
11    for (k, v) in t.color.entries() {
12        color.insert(
13            k.replace('_', "-"),
14            json!({ "$type": "color", "$value": v.hex() }),
15        );
16    }
17    root.insert("color".into(), Value::Object(color));
18
19    // spacing
20    let mut spacing = Map::new();
21    for (k, v) in t.spacing.pairs() {
22        spacing.insert(
23            k.into(),
24            json!({ "$type": "dimension", "$value": format!("{v}px") }),
25        );
26    }
27    root.insert("spacing".into(), Value::Object(spacing));
28
29    // radius
30    let mut radius = Map::new();
31    for (k, v) in t.radius.pairs() {
32        radius.insert(
33            k.into(),
34            json!({ "$type": "dimension", "$value": format!("{v}px") }),
35        );
36    }
37    root.insert("radius".into(), Value::Object(radius));
38
39    // fontFamily
40    let f = &t.typography.families;
41    root.insert(
42        "fontFamily".into(),
43        json!({
44            "serif":   { "$type": "fontFamily", "$value": f.serif },
45            "sans":    { "$type": "fontFamily", "$value": f.sans },
46            "mono":    { "$type": "fontFamily", "$value": f.mono },
47            "display": { "$type": "fontFamily", "$value": f.display },
48        }),
49    );
50
51    serde_json::to_string_pretty(&root).unwrap()
52}