Reduce json nesting
diff --git a/codegen/src/gen.rs b/codegen/src/gen.rs
index 9f622b9..c954961 100644
--- a/codegen/src/gen.rs
+++ b/codegen/src/gen.rs
@@ -340,7 +340,9 @@
         match ty {
             types::Type::Box(t) => box_visit(&*t, features, types, kind, name),
             types::Type::Vec(t) => vec_visit(&*t, features, types, kind, name),
-            types::Type::Punctuated(t, _) => punctuated_visit(&*t, features, types, kind, name),
+            types::Type::Punctuated(p) => {
+                punctuated_visit(p.element(), features, types, kind, name)
+            }
             types::Type::Option(t) => option_visit(&*t, features, types, kind, name),
             types::Type::Tuple(t) => tuple_visit(t, features, types, kind, name),
             types::Type::Token(t) => {
@@ -350,7 +352,7 @@
                     Some(token_punct_visit(t, kind, name))
                 }
             }
-            types::Type::TokenGroup(t) => Some(token_group_visit(&t[..], kind, name)),
+            types::Type::Group(t) => Some(token_group_visit(&t[..], kind, name)),
             types::Type::Item(t) => {
                 fn requires_full(features: &types::Features) -> bool {
                     features.contains("full") && features.len() == 1
diff --git a/codegen/src/parse.rs b/codegen/src/parse.rs
index e7eef19..25b8ac1 100644
--- a/codegen/src/parse.rs
+++ b/codegen/src/parse.rs
@@ -162,7 +162,7 @@
                         _ => panic!(),
                     };
 
-                    types::Type::Punctuated(Box::new(nested), punct)
+                    types::Type::Punctuated(types::Punctuated::new(nested, punct))
                 }
                 "Vec" => {
                     let nested = introspect_type(first_arg(&last.arguments), items, tokens);
@@ -173,7 +173,7 @@
                     types::Type::Box(Box::new(nested))
                 }
                 "Brace" | "Bracket" | "Paren" | "Group" => {
-                    types::Type::TokenGroup(last.ident.to_string())
+                    types::Type::Group(last.ident.to_string())
                 }
                 "TokenStream" | "Literal" => types::Type::Ext(last.ident.to_string()),
                 "String" | "u32" | "usize" | "bool" => types::Type::Std(last.ident.to_string()),
diff --git a/codegen/src/types.rs b/codegen/src/types.rs
index 3770f41..679b72e 100644
--- a/codegen/src/types.rs
+++ b/codegen/src/types.rs
@@ -1,7 +1,7 @@
 use std::ops;
 
 #[derive(Debug, Serialize)]
-#[serde(rename_all = "snake_case")]
+#[serde(tag = "node", rename_all = "lowercase")]
 pub enum TypeDef {
     Struct(Struct),
     Enum(Enum),
@@ -31,11 +31,12 @@
 #[derive(Debug, Serialize)]
 pub struct Field {
     ident: String,
+    #[serde(rename = "type")]
     ty: Type,
 }
 
 #[derive(Debug, Serialize)]
-#[serde(rename_all = "snake_case")]
+#[serde(rename_all = "lowercase")]
 pub enum Type {
     /// Type defined by `syn`
     Item(String),
@@ -50,10 +51,11 @@
     Token(Token),
 
     /// Token group
-    TokenGroup(String),
+    Group(String),
 
     /// Punctuated list
-    Punctuated(Box<Type>, Token),
+    Punctuated(Punctuated),
+
     Option(Box<Type>),
     Box(Box<Type>),
     Vec(Box<Type>),
@@ -63,9 +65,16 @@
 #[derive(Debug, Clone, Serialize)]
 pub struct Token {
     repr: String,
+    #[serde(rename = "type")]
     ty: String,
 }
 
+#[derive(Debug, Serialize)]
+pub struct Punctuated {
+    element: Box<Type>,
+    punct: Token,
+}
+
 #[derive(Debug, Default, Clone, Serialize)]
 pub struct Features {
     any: Vec<String>,
@@ -172,6 +181,16 @@
     }
 }
 
+impl Punctuated {
+    pub fn new(element: Type, punct: Token) -> Self {
+        Punctuated { element: Box::new(element), punct }
+    }
+
+    pub fn element(&self) -> &Type {
+        &self.element
+    }
+}
+
 impl Features {
     pub fn new(any: Vec<String>) -> Features {
         Features { any }