Commit 2a96f80d03

Loris Cro <kappaloris@gmail.com>
2022-09-10 21:08:26
autodoc: reduce json payload size
this commit removes whitespace and changes Decl, AstNode and Type to be json arrays instead of json objects. This change reduces json payload size for the stdlib from 25mb to < 10mb.
1 parent 81939a4
Changed files (2)
lib
docs
src
lib/docs/main.js
@@ -203,7 +203,7 @@ var zigAnalysis;
     if (!("type" in resolvedExpr)) {
       return null;
     }
-    let type = zigAnalysis.types[resolvedExpr.type];
+    let type = getType(resolvedExpr.type);
 
     outer: for (let i = 0; i < 10000; i += 1) {
       switch (type.kind) {
@@ -212,7 +212,7 @@ var zigAnalysis;
           let child = type.child;
           let resolvedChild = resolveValue(child);
           if ("type" in resolvedChild) {
-            type = zigAnalysis.types[resolvedChild.type];
+            type = getType(resolvedChild.type);
             continue;
           } else {
             return null;
@@ -276,7 +276,7 @@ var zigAnalysis;
       }
 
       if ("declRef" in value.expr) {
-        value = zigAnalysis.decls[value.expr.declRef].value;
+        value = getDecl(value.expr.declRef).value;
         continue;
       }
 
@@ -430,7 +430,7 @@ var zigAnalysis;
       curNav.pkgObjs.push(pkg);
     }
 
-    let currentType = zigAnalysis.types[pkg.main];
+    let currentType = getType(pkg.main);
     curNav.declObjs = [currentType];
     for (let i = 0; i < curNav.declNames.length; i += 1) {
       let childDecl = findSubDecl(currentType, curNav.declNames[i]);
@@ -440,7 +440,7 @@ var zigAnalysis;
 
       let childDeclValue = resolveValue(childDecl.value).expr;
       if ("type" in childDeclValue) {
-        const t = zigAnalysis.types[childDeclValue.type];
+        const t = getType(childDeclValue.type);
         if (t.kind != typeKinds.Fn) {
           childDecl = t;
         }
@@ -478,7 +478,7 @@ var zigAnalysis;
     }
 
     if (lastIsDecl && last.kind === "const") {
-      let typeObj = zigAnalysis.types[resolveValue(last.value).expr.type];
+      let typeObj = getType(resolveValue(last.value).expr.type);
       if (typeObj && typeObj.kind === typeKinds.Fn) {
         return renderFn(last);
       }
@@ -489,8 +489,8 @@ var zigAnalysis;
   }
     
   function renderDocTest(decl) {
-    if (!("decltest" in decl)) return;
-    const astNode = zigAnalysis.astNodes[decl.decltest];
+    if (!decl.decltest) return;
+    const astNode = getAstNode(decl.decltest);
     domSectDocTests.classList.remove("hidden");
     domDocTestsCode.innerHTML = astNode.code;
   }
@@ -498,7 +498,7 @@ var zigAnalysis;
   function renderUnknownDecl(decl) {
     domDeclNoRef.classList.remove("hidden");
 
-    let docs = zigAnalysis.astNodes[decl.src].docs;
+    let docs = getAstNode(decl.src).docs;
     if (docs != null) {
       domTldDocs.innerHTML = markdown(docs);
     } else {
@@ -509,18 +509,18 @@ var zigAnalysis;
   }
 
   function typeIsErrSet(typeIndex) {
-    let typeObj = zigAnalysis.types[typeIndex];
+    let typeObj = getType(typeIndex);
     return typeObj.kind === typeKinds.ErrorSet;
   }
 
   function typeIsStructWithNoFields(typeIndex) {
-    let typeObj = zigAnalysis.types[typeIndex];
+    let typeObj = getType(typeIndex);
     if (typeObj.kind !== typeKinds.Struct) return false;
     return typeObj.fields.length == 0;
   }
 
   function typeIsGenericFn(typeIndex) {
-    let typeObj = zigAnalysis.types[typeIndex];
+    let typeObj = getType(typeIndex);
     if (typeObj.kind !== typeKinds.Fn) {
       return false;
     }
@@ -532,12 +532,12 @@ var zigAnalysis;
       let last = fnDecl.value.expr.refPath.length - 1;
       let lastExpr = fnDecl.value.expr.refPath[last];
       console.assert("declRef" in lastExpr);
-      fnDecl = zigAnalysis.decls[lastExpr.declRef];
+      fnDecl = getDecl(lastExpr.declRef);
     }
 
     let value = resolveValue(fnDecl.value);
     console.assert("type" in value.expr);
-    let typeObj = zigAnalysis.types[value.expr.type];
+    let typeObj = getType(value.expr.type);
 
     domFnProtoCode.innerHTML = exprName(value.expr, {
       wantHtml: true,
@@ -546,7 +546,7 @@ var zigAnalysis;
     });
 
     let docsSource = null;
-    let srcNode = zigAnalysis.astNodes[fnDecl.src];
+    let srcNode = getAstNode(fnDecl.src);
     if (srcNode.docs != null) {
       docsSource = srcNode.docs;
     }
@@ -557,14 +557,14 @@ var zigAnalysis;
     if ("type" in retExpr) {
       let retIndex = retExpr.type;
       let errSetTypeIndex = null;
-      let retType = zigAnalysis.types[retIndex];
+      let retType = getType(retIndex);
       if (retType.kind === typeKinds.ErrorSet) {
         errSetTypeIndex = retIndex;
       } else if (retType.kind === typeKinds.ErrorUnion) {
         errSetTypeIndex = retType.err.type;
       }
       if (errSetTypeIndex != null) {
-        let errSetType = zigAnalysis.types[errSetTypeIndex];
+        let errSetType = getType(errSetTypeIndex);
         renderErrorSet(errSetType);
       }
     }
@@ -578,7 +578,7 @@ var zigAnalysis;
         let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
         let resolvedFunc = resolveValue({ expr: call.func });
         if (!("type" in resolvedFunc.expr)) return;
-        let callee = zigAnalysis.types[resolvedFunc.expr.type];
+        let callee = getType(resolvedFunc.expr.type);
         if (!callee.generic_ret) return;
         resolvedGenericRet = resolveValue({ expr: callee.generic_ret });
       }
@@ -591,7 +591,7 @@ var zigAnalysis;
       }
 
       if (!("type" in resolvedGenericRet.expr)) return;
-      const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];
+      const genericType = getType(resolvedGenericRet.expr.type);
       if (isContainerType(genericType)) {
         renderContainer(genericType);
       }
@@ -621,7 +621,7 @@ var zigAnalysis;
       domFnNoExamples.classList.add("hidden");
     }
 
-    let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
+    let protoSrcNode = getAstNode(protoSrcIndex);
     if (
       docsSource == null &&
       protoSrcNode != null &&
@@ -639,13 +639,13 @@ var zigAnalysis;
   function renderFnParamDocs(fnDecl, typeObj) {
     let docCount = 0;
 
-    let fnNode = zigAnalysis.astNodes[fnDecl.src];
+    let fnNode = getAstNode(fnDecl.src);
     let fields = fnNode.fields;
     let isVarArgs = fnNode.varArgs;
 
     for (let i = 0; i < fields.length; i += 1) {
       let field = fields[i];
-      let fieldNode = zigAnalysis.astNodes[field];
+      let fieldNode = getAstNode(field);
       if (fieldNode.docs != null) {
         docCount += 1;
       }
@@ -659,7 +659,7 @@ var zigAnalysis;
 
     for (let i = 0; i < fields.length; i += 1) {
       let field = fields[i];
-      let fieldNode = zigAnalysis.astNodes[field];
+      let fieldNode = getAstNode(field);
       let docs = fieldNode.docs;
       if (fieldNode.docs == null) {
         continue;
@@ -967,17 +967,17 @@ var zigAnalysis;
       }
       case "switchOp": {
         let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index];
-        let ast = zigAnalysis.astNodes[expr.switchOp.ast];
+        let ast = getAstNode(expr.switchOp.src);
         let file_name = expr.switchOp.file_name;
         let outer_decl_index = expr.switchOp.outer_decl;
-        let outer_decl = zigAnalysis.types[outer_decl_index];
+        let outer_decl = getType(outer_decl_index);
         let line = 0;
         // console.log(expr.switchOp)
         // console.log(outer_decl)
         while (outer_decl_index !== 0 && outer_decl.line_number > 0) {
           line += outer_decl.line_number;
           outer_decl_index = outer_decl.outer_decl;
-          outer_decl = zigAnalysis.types[outer_decl_index];
+          outer_decl = getType(outer_decl_index);
           // console.log(outer_decl)
         }
         line += ast.line + 1;
@@ -1028,8 +1028,8 @@ var zigAnalysis;
       case "fieldRef": {
         const enumObj = exprName({ type: expr.fieldRef.type }, opts);
         const field =
-          zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];
-        const name = zigAnalysis.astNodes[field].name;
+          getAstNode(enumObj.src).fields[expr.fieldRef.index];
+        const name = getAstNode(field).name;
         return name;
       }
       case "enumToInt": {
@@ -1452,13 +1452,13 @@ var zigAnalysis;
         return print_lhs + " " + operator + " " + print_rhs;
       }
       case "errorSets": {
-        const errUnionObj = zigAnalysis.types[expr.errorSets];
+        const errUnionObj = getType(expr.errorSets);
         let lhs = exprName(errUnionObj.lhs, opts);
         let rhs = exprName(errUnionObj.rhs, opts);
         return lhs + " || " + rhs;
       }
       case "errorUnion": {
-        const errUnionObj = zigAnalysis.types[expr.errorUnion];
+        const errUnionObj = getType(expr.errorUnion);
         let lhs = exprName(errUnionObj.lhs, opts);
         let rhs = exprName(errUnionObj.rhs, opts);
         return lhs + "!" + rhs;
@@ -1574,7 +1574,7 @@ var zigAnalysis;
         return exprName(exprArg, opts);
       }
       case "declRef": {
-        return zigAnalysis.decls[expr.declRef].name;
+        return getDecl(expr.declRef).name;
       }
       case "refPath": {
         return expr.refPath.map((x) => exprName(x, opts)).join(".");
@@ -1611,7 +1611,7 @@ var zigAnalysis;
         let name = "";
 
         let typeObj = expr.type;
-        if (typeof typeObj === "number") typeObj = zigAnalysis.types[typeObj];
+        if (typeof typeObj === "number") typeObj = getType(typeObj);
         switch (typeObj.kind) {
           default:
             throw "TODO";
@@ -1865,7 +1865,7 @@ var zigAnalysis;
             if (fnObj.params) {
               let fields = null;
               let isVarArgs = false;
-              let fnNode = zigAnalysis.astNodes[fnObj.src];
+              let fnNode = getAstNode(fnObj.src);
               fields = fnNode.fields;
               isVarArgs = fnNode.varArgs;
 
@@ -1880,7 +1880,7 @@ var zigAnalysis;
                 let paramValue = resolveValue({ expr: value });
 
                 if (fields != null) {
-                  let paramNode = zigAnalysis.astNodes[fields[i]];
+                  let paramNode = getAstNode(fields[i]);
 
                   if (paramNode.varArgs) {
                     payloadHtml += "...";
@@ -2046,7 +2046,7 @@ var zigAnalysis;
   function shouldSkipParamName(typeRef, paramName) {
     let resolvedTypeRef = resolveValue({ expr: typeRef });
     if ("type" in resolvedTypeRef) {
-      let typeObj = zigAnalysis.types[resolvedTypeRef.type];
+      let typeObj = getType(resolvedTypeRef.type);
       if (typeObj.kind === typeKinds.Pointer) {
         let ptrObj = typeObj;
         if (getPtrSize(ptrObj) === pointerSizeEnum.One) {
@@ -2067,7 +2067,7 @@ var zigAnalysis;
     if (
       rootIsStd &&
       typeObj ===
-        zigAnalysis.types[zigAnalysis.packages[zigAnalysis.rootPkg].main]
+        getType(zigAnalysis.packages[zigAnalysis.rootPkg].main)
     ) {
       name = "std";
     } else {
@@ -2189,7 +2189,7 @@ var zigAnalysis;
 
     if (resolvedValue.expr.fieldRef) {
       const declRef = decl.value.expr.refPath[0].declRef;
-      const type = zigAnalysis.decls[declRef];
+      const type = getDecl(declRef);
       domFnProtoCode.innerHTML =
         '<span class="tok-kw">const</span> ' +
         escapeHtml(decl.name) +
@@ -2229,7 +2229,7 @@ var zigAnalysis;
         ";";
     }
 
-    let docs = zigAnalysis.astNodes[decl.src].docs;
+    let docs = getAstNode(decl.src).docs;
     if (docs != null) {
       domTldDocs.innerHTML = markdown(docs);
       domTldDocs.classList.remove("hidden");
@@ -2246,7 +2246,7 @@ var zigAnalysis;
       ": " +
       typeValueName(declTypeRef, true, true);
 
-    let docs = zigAnalysis.astNodes[decl.src].docs;
+    let docs = getAstNode(decl.src).docs;
     if (docs != null) {
       domTldDocs.innerHTML = markdown(docs);
       domTldDocs.classList.remove("hidden");
@@ -2266,7 +2266,7 @@ var zigAnalysis;
     testsList
   ) {
     for (let i = 0; i < decls.length; i += 1) {
-      let decl = zigAnalysis.decls[decls[i]];
+      let decl = getDecl(decls[i]);
       let declValue = resolveValue(decl.value);
 
       if (decl.isTest) {
@@ -2282,7 +2282,7 @@ var zigAnalysis;
       if (decl.kind === "const") {
         if ("type" in declValue.expr) {
           // We have the actual type expression at hand.
-          const typeExpr = zigAnalysis.types[declValue.expr.type];
+          const typeExpr = getType(declValue.expr.type);
           if (typeExpr.kind == typeKinds.Fn) {
             const funcRetExpr = resolveValue({
               expr: typeExpr.ret,
@@ -2310,7 +2310,7 @@ var zigAnalysis;
               typesList.push(decl);
             }
           }
-        } else if ("typeRef" in declValue) {
+        } else if (declValue.typeRef) {
           if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {
             // We don't know what the type expression is, but we know it's a type.
             typesList.push(decl);
@@ -2324,7 +2324,7 @@ var zigAnalysis;
     }
   }
   function renderSourceFileLink(decl) {
-    let srcNode = zigAnalysis.astNodes[decl.src];
+    let srcNode = getAstNode(decl.src);
 
     return  "<a style=\"float: right;\" href=\"" +
       sourceFileUrlTemplate.replace("{{file}}",
@@ -2377,7 +2377,7 @@ var zigAnalysis;
     testsList.sort(byNameProperty);
 
     if (container.src != null) {
-      let docs = zigAnalysis.astNodes[container.src].docs;
+      let docs = getAstNode(container.src).docs;
       if (docs != null) {
         domTldDocs.innerHTML = markdown(docs);
         domTldDocs.classList.remove("hidden");
@@ -2457,7 +2457,7 @@ var zigAnalysis;
         });
         tdFnSrc.innerHTML = renderSourceFileLink(decl);
 
-        let docs = zigAnalysis.astNodes[decl.src].docs;
+        let docs = getAstNode(decl.src).docs;
         if (docs != null) {
           tdDesc.innerHTML = shortDescMarkdown(docs);
         } else {
@@ -2467,12 +2467,12 @@ var zigAnalysis;
       domSectFns.classList.remove("hidden");
     }
 
-    let containerNode = zigAnalysis.astNodes[container.src];
+    let containerNode = getAstNode(container.src);
     if (containerNode.fields && containerNode.fields.length > 0) {
       resizeDomList(domListFields, containerNode.fields.length, "<div></div>");
 
       for (let i = 0; i < containerNode.fields.length; i += 1) {
-        let fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
+        let fieldNode = getAstNode(containerNode.fields[i]);
         let divDom = domListFields.children[i];
         let fieldName = fieldNode.name;
         let docs = fieldNode.docs;
@@ -2528,7 +2528,7 @@ var zigAnalysis;
 
         tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
 
-        let docs = zigAnalysis.astNodes[decl.src].docs;
+        let docs = getAstNode(decl.src).docs;
         if (docs != null) {
           tdDesc.innerHTML = shortDescMarkdown(docs);
         } else {
@@ -2561,7 +2561,7 @@ var zigAnalysis;
           wantLink: true,
         });
 
-        let docs = zigAnalysis.astNodes[decl.src].docs;
+        let docs = getAstNode(decl.src).docs;
         if (docs != null) {
           tdDesc.innerHTML = shortDescMarkdown(docs);
         } else {
@@ -2594,7 +2594,7 @@ var zigAnalysis;
           wantLink: true,
         });
 
-        let docs = zigAnalysis.astNodes[decl.src].docs;
+        let docs = getAstNode(decl.src).docs;
         if (docs != null) {
           tdDesc.innerHTML = shortDescMarkdown(docs);
         } else {
@@ -2668,7 +2668,7 @@ var zigAnalysis;
 
   function findTypeTypeId() {
     for (let i = 0; i < zigAnalysis.types.length; i += 1) {
-      if (zigAnalysis.types[i].kind == typeKinds.Type) {
+      if (getType(i).kind == typeKinds.Type) {
         return i;
       }
     }
@@ -2732,11 +2732,11 @@ var zigAnalysis;
       if ("value" in parentType) {
         const rv = resolveValue(parentType.value);
         if ("type" in rv.expr) {
-          const t = zigAnalysis.types[rv.expr.type];
+          const t = getType(rv.expr.type);
           if (t.kind == typeKinds.Fn && t.generic_ret != null) {
             const rgr = resolveValue({ expr: t.generic_ret });
             if ("type" in rgr.expr) {
-              parentType = zigAnalysis.types[rgr.expr.type];
+              parentType = getType(rgr.expr.type);
             }
           }
         }
@@ -2746,7 +2746,7 @@ var zigAnalysis;
     if (!parentType.pubDecls) return null;
     for (let i = 0; i < parentType.pubDecls.length; i += 1) {
       let declIndex = parentType.pubDecls[i];
-      let childDecl = zigAnalysis.decls[declIndex];
+      let childDecl = getDecl(declIndex);
       if (childDecl.name === childName) {
         return childDecl;
       }
@@ -2754,7 +2754,7 @@ var zigAnalysis;
     if (!parentType.privDecls) return null;
     for (let i = 0; i < parentType.privDecls.length; i += 1) {
       let declIndex = parentType.privDecls[i];
-      let childDecl = zigAnalysis.decls[declIndex];
+      let childDecl = getDecl(declIndex);
       if (childDecl.name === childName) {
         return childDecl;
       }
@@ -2805,7 +2805,7 @@ var zigAnalysis;
       let stack = [
         {
           declNames: [],
-          type: zigAnalysis.types[pkg.main],
+          type: getType(pkg.main),
         },
       ];
       while (stack.length !== 0) {
@@ -2819,7 +2819,7 @@ var zigAnalysis;
             let mainDeclIndex = t.pubDecls[declI];
             if (list[mainDeclIndex] != null) continue;
 
-            let decl = zigAnalysis.decls[mainDeclIndex];
+            let decl = getDecl(mainDeclIndex);
             let declVal = resolveValue(decl.value);
             let declNames = item.declNames.concat([decl.name]);
             list[mainDeclIndex] = {
@@ -2827,7 +2827,7 @@ var zigAnalysis;
               declNames: declNames,
             };
             if ("type" in declVal.expr) {
-              let value = zigAnalysis.types[declVal.expr.type];
+              let value = getType(declVal.expr.type);
               if (declCanRepresentTypeKind(value.kind)) {
                 canonTypeDecls[declVal.type] = mainDeclIndex;
               }
@@ -2843,7 +2843,7 @@ var zigAnalysis;
               if (value.kind == typeKinds.Fn && value.generic_ret != null) {
                 let resolvedVal = resolveValue({ expr: value.generic_ret });
                 if ("type" in resolvedVal.expr) {
-                  let generic_type = zigAnalysis.types[resolvedVal.expr.type];
+                  let generic_type = getType(resolvedVal.expr.type);
                   if (isContainerType(generic_type)) {
                     stack.push({
                       declNames: declNames,
@@ -3394,11 +3394,11 @@ var zigAnalysis;
       let canonPath = getCanonDeclPath(declIndex);
       if (canonPath == null) continue;
 
-      let decl = zigAnalysis.decls[declIndex];
+      let decl = getDecl(declIndex);
       let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
       let fullPathSearchText =
         lastPkgName + "." + canonPath.declNames.join(".");
-      let astNode = zigAnalysis.astNodes[decl.src];
+      let astNode = getAstNode(decl.src);
       let fileAndDocs = ""; //zigAnalysis.files[astNode.file];
       // TODO: understand what this piece of code is trying to achieve
       //       also right now `files` are expressed as a hashmap.
@@ -3513,4 +3513,169 @@ var zigAnalysis;
   function byNameProperty(a, b) {
     return operatorCompare(a.name, b.name);
   }
+
+
+  function getDecl(idx) {
+    const decl = zigAnalysis.decls[idx];
+    return {
+      name: decl[0],
+      kind: decl[1],
+      isTest: decl[2],
+      src: decl[3],
+      value: decl[4],
+      decltest: decl[5],
+    };
+  }
+  
+  function getAstNode(idx) {
+    const ast = zigAnalysis.astNodes[idx];
+    return {
+      file: ast[0],
+      line: ast[1],
+      col: ast[2],
+      name: ast[3],
+      code: ast[4],
+      docs: ast[5],
+      fields: ast[6],
+      comptime: ast[7],
+    };
+  }
+  
+  function getType(idx){
+    const ty = zigAnalysis.types[idx];
+    switch(ty[0]) {
+    default: 
+      throw "unhandled type kind!";
+    case 0: // Unanalyzed
+      throw "unanalyzed type!";
+    case 1: // Type
+    case 2: // Void 
+    case 3: //  Bool
+    case 4: //  NoReturn
+    case 5: //  Int
+    case 6: //  Float
+      return { kind: ty[0], name: ty[1]};
+    case 7: // Pointer
+      return {
+        kind: ty[0],
+        size: ty[1],
+        child: ty[2],
+        sentinel: ty[3],
+        align: ty[4],
+        address_space: ty[5],
+        bit_start: ty[6],
+        host_size: ty[7],
+        is_ref: ty[8],
+        is_allowzero: ty[9],
+        is_mutable: ty[10],
+        is_volatile: ty[11],
+        has_sentinel: ty[12],
+        has_align: ty[13],
+        has_addrspace: ty[14],
+        has_bit_range: ty[15],
+      };
+    case 8: // Array
+      return {
+        kind: ty[0],
+        len: ty[1],
+        child: ty[2],
+        sentinel: ty[3],
+      };
+    case 9: // Struct
+      return {
+        kind: ty[0],
+        name: ty[1],
+        src: ty[2],
+        privDecls: ty[3],
+        pubDecls: ty[4],
+        fields: ty[5],
+        line_number: ty[6],
+        outer_decl: ty[7],
+      };
+    case 10: // ComptimeExpr
+    case 11: // ComptimeFloat
+    case 12: // ComptimeInt
+    case 13: // Undefined
+    case 14: // Null
+      return { kind: ty[0], name: ty[1] };
+    case 15: // Optional
+      return {
+        kind: ty[0],
+        name: ty[1],
+        child: ty[2],
+      };
+    case 16: // ErrorUnion
+      return {
+        kind: ty[0],
+        lhs: ty[1],
+        rhs: ty[2],
+      };
+    case 17: // InferredErrorUnion
+      return {
+        kind: ty[0],
+        payload: ty[1],
+      };
+    case 18: // ErrorSet
+      return {
+        kind: ty[0],
+        name: ty[1],
+        fields: ty[2],
+      };
+    case 19: // Enum
+      return {
+        kind: ty[0],
+        name: ty[1],
+        src: ty[2],
+        privDecls: ty[3],
+        pubDecls: ty[4],
+      };
+    case 20: // Union
+      return {
+        kind: ty[0],
+        name: ty[1],
+        src: ty[2],
+        privDecls: ty[3],
+        pubDecls: ty[4],
+        fields: ty[5],
+      };    
+    case 21: // Fn
+      return {
+        kind: ty[0],
+        name: ty[1],
+        src: ty[2],
+        ret: ty[3],
+        generic_ret: ty[4],
+        params: ty[5],
+        lib_name: ty[6],
+        is_var_args: ty[7],
+        is_inferred_error: ty[8],
+        has_lib_name: ty[9],
+        has_cc: ty[10],
+        cc: ty[11],
+        align: ty[12],
+        has_align: ty[13],
+        is_test: ty[14],
+        is_extern: ty[15],
+      };
+    case 22: // BoundFn
+      return { kind: ty[0], name: ty[1] };
+    case 23: // Opaque
+      return {
+        kind: ty[0],
+        name: ty[1],
+        src: ty[2],
+        privDecls: ty[3],
+        pubDecls: ty[4],
+      };
+    case 24: // Frame
+    case 25: // AnyFrame
+    case 26: // Vector
+    case 27: // EnumLiteral
+      return { kind: ty[0], name: ty[1] };
+    }
+  }
+  
 })();
+
+
+
src/Autodoc.zig
@@ -280,8 +280,8 @@ pub fn generateZirData(self: *Autodoc) !void {
         try std.json.stringify(
             data,
             .{
-                .whitespace = .{ .indent = if (builtin.mode == .Debug) .{ .Space = 4 } else .None },
-                .emit_null_optional_fields = false,
+                .whitespace = .{ .indent = .None, .separator = false },
+                .emit_null_optional_fields = true,
             },
             out,
         );
@@ -404,6 +404,7 @@ const DocData = struct {
         w: anytype,
     ) !void {
         var jsw = std.json.writeStream(w, 15);
+        if (opts.whitespace) |ws| jsw.whitespace = ws;
         try jsw.beginObject();
         inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {
             const f_name = @tagName(f);
@@ -449,6 +450,8 @@ const DocData = struct {
             w: anytype,
         ) !void {
             var jsw = std.json.writeStream(w, 15);
+            if (opts.whitespace) |ws| jsw.whitespace = ws;
+
             try jsw.beginObject();
             inline for (comptime std.meta.tags(std.meta.FieldEnum(DocPackage))) |f| {
                 const f_name = @tagName(f);
@@ -474,6 +477,22 @@ const DocData = struct {
         // The index in astNodes of the `test declname { }` node
         decltest: ?usize = null,
         _analyzed: bool, // omitted in json data
+
+        pub fn jsonStringify(
+            self: Decl,
+            opts: std.json.StringifyOptions,
+            w: anytype,
+        ) !void {
+            var jsw = std.json.writeStream(w, 15);
+            if (opts.whitespace) |ws| jsw.whitespace = ws;
+            try jsw.beginArray();
+            inline for (comptime std.meta.fields(Decl)) |f| {
+                try jsw.arrayElem();
+                try std.json.stringify(@field(self, f.name), opts, w);
+                jsw.state_index -= 1;
+            }
+            try jsw.endArray();
+        }
     };
 
     const AstNode = struct {
@@ -485,6 +504,22 @@ const DocData = struct {
         docs: ?[]const u8 = null,
         fields: ?[]usize = null, // index into astNodes
         @"comptime": bool = false,
+
+        pub fn jsonStringify(
+            self: AstNode,
+            opts: std.json.StringifyOptions,
+            w: anytype,
+        ) !void {
+            var jsw = std.json.writeStream(w, 15);
+            if (opts.whitespace) |ws| jsw.whitespace = ws;
+            try jsw.beginArray();
+            inline for (comptime std.meta.fields(AstNode)) |f| {
+                try jsw.arrayElem();
+                try std.json.stringify(@field(self, f.name), opts, w);
+                jsw.state_index -= 1;
+            }
+            try jsw.endArray();
+        }
     };
 
     const Type = union(enum) {
@@ -525,7 +560,6 @@ const DocData = struct {
             fields: ?[]Expr = null, // (use src->fields to find names)
             line_number: usize,
             outer_decl: usize,
-            ast: usize,
         },
         ComptimeExpr: struct { name: []const u8 },
         ComptimeFloat: struct { name: []const u8 },
@@ -548,7 +582,6 @@ const DocData = struct {
             src: usize, // index into astNodes
             privDecls: []usize = &.{}, // index into decls
             pubDecls: []usize = &.{}, // index into decls
-            ast: usize,
             // (use src->fields to find field names)
         },
         Union: struct {
@@ -557,7 +590,6 @@ const DocData = struct {
             privDecls: []usize = &.{}, // index into decls
             pubDecls: []usize = &.{}, // index into decls
             fields: []Expr = &.{}, // (use src->fields to find names)
-            ast: usize,
         },
         Fn: struct {
             name: []const u8,
@@ -582,7 +614,6 @@ const DocData = struct {
             src: usize, // index into astNodes
             privDecls: []usize = &.{}, // index into decls
             pubDecls: []usize = &.{}, // index into decls
-            ast: usize,
         },
         Frame: struct { name: []const u8 },
         AnyFrame: struct { name: []const u8 },
@@ -601,14 +632,15 @@ const DocData = struct {
         ) !void {
             const active_tag = std.meta.activeTag(self);
             var jsw = std.json.writeStream(w, 15);
-            try jsw.beginObject();
-            try jsw.objectField("kind");
+            if (opts.whitespace) |ws| jsw.whitespace = ws;
+            try jsw.beginArray();
+            try jsw.arrayElem();
             try jsw.emitNumber(@enumToInt(active_tag));
             inline for (comptime std.meta.fields(Type)) |case| {
                 if (@field(Type, case.name) == active_tag) {
                     const current_value = @field(self, case.name);
                     inline for (comptime std.meta.fields(case.field_type)) |f| {
-                        try jsw.objectField(f.name);
+                        try jsw.arrayElem();
                         if (f.field_type == std.builtin.TypeInfo.Pointer.Size) {
                             try jsw.emitNumber(@enumToInt(@field(current_value, f.name)));
                         } else {
@@ -618,7 +650,7 @@ const DocData = struct {
                     }
                 }
             }
-            try jsw.endObject();
+            try jsw.endArray();
         }
     };
 
@@ -686,7 +718,7 @@ const DocData = struct {
         const SwitchOp = struct {
             cond_index: usize,
             file_name: []const u8,
-            ast: usize,
+            src: usize,
             outer_decl: usize, // index in `types`
         };
         const BuiltinBin = struct {
@@ -704,7 +736,15 @@ const DocData = struct {
             end: ?usize = null,
             sentinel: ?usize = null, // index in `exprs`
         };
-        const Cmpxchg = struct { name: []const u8, type: usize, ptr: usize, expected_value: usize, new_value: usize, success_order: usize, failure_order: usize };
+        const Cmpxchg = struct {
+            name: []const u8,
+            type: usize,
+            ptr: usize,
+            expected_value: usize,
+            new_value: usize,
+            success_order: usize,
+            failure_order: usize,
+        };
         const As = struct {
             typeRefArg: ?usize, // index in `exprs`
             exprArg: usize, // index in `exprs`
@@ -721,11 +761,12 @@ const DocData = struct {
 
         pub fn jsonStringify(
             self: Expr,
-            opt: std.json.StringifyOptions,
+            opts: std.json.StringifyOptions,
             w: anytype,
         ) !void {
             const active_tag = std.meta.activeTag(self);
             var jsw = std.json.writeStream(w, 15);
+            if (opts.whitespace) |ws| jsw.whitespace = ws;
             try jsw.beginObject();
             try jsw.objectField(@tagName(active_tag));
             switch (self) {
@@ -742,7 +783,7 @@ const DocData = struct {
                         if (comptime std.mem.eql(u8, case.name, "builtinField"))
                             continue;
                         if (@field(Expr, case.name) == active_tag) {
-                            try std.json.stringify(@field(self, case.name), opt, w);
+                            try std.json.stringify(@field(self, case.name), opts, w);
                             jsw.state_index -= 1;
                             // TODO: we should not reach into the state of the
                             //       json writer, but alas, this is what's
@@ -1874,7 +1915,12 @@ fn walkInstruction(
             // log.debug("{s}", .{sep});
 
             const switch_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .switchOp = .{ .cond_index = cond_index, .file_name = file.sub_file_path, .ast = ast_index, .outer_decl = type_index } });
+            try self.exprs.append(self.arena, .{ .switchOp = .{
+                .cond_index = cond_index,
+                .file_name = file.sub_file_path,
+                .src = ast_index,
+                .outer_decl = type_index,
+            } });
 
             return DocData.WalkResult{
                 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
@@ -2505,7 +2551,6 @@ fn walkInstruction(
                             .src = self_ast_node_index,
                             .privDecls = priv_decl_indexes.items,
                             .pubDecls = decl_indexes.items,
-                            .ast = self_ast_node_index,
                         },
                     };
                     if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
@@ -2644,7 +2689,13 @@ fn walkInstruction(
                     self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
 
                     self.types.items[type_slot_index] = .{
-                        .Union = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .fields = field_type_refs.items, .ast = self_ast_node_index },
+                        .Union = .{
+                            .name = "todo_name",
+                            .src = self_ast_node_index,
+                            .privDecls = priv_decl_indexes.items,
+                            .pubDecls = decl_indexes.items,
+                            .fields = field_type_refs.items,
+                        },
                     };
 
                     if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
@@ -2796,7 +2847,12 @@ fn walkInstruction(
                     self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
 
                     self.types.items[type_slot_index] = .{
-                        .Enum = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .ast = self_ast_node_index },
+                        .Enum = .{
+                            .name = "todo_name",
+                            .src = self_ast_node_index,
+                            .privDecls = priv_decl_indexes.items,
+                            .pubDecls = decl_indexes.items,
+                        },
                     };
                     if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
                         for (paths.items) |resume_info| {
@@ -2910,7 +2966,15 @@ fn walkInstruction(
                     self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
 
                     self.types.items[type_slot_index] = .{
-                        .Struct = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .fields = field_type_refs.items, .line_number = self.ast_nodes.items[self_ast_node_index].line, .outer_decl = type_slot_index - 1, .ast = self_ast_node_index },
+                        .Struct = .{
+                            .name = "todo_name",
+                            .src = self_ast_node_index,
+                            .privDecls = priv_decl_indexes.items,
+                            .pubDecls = decl_indexes.items,
+                            .fields = field_type_refs.items,
+                            .line_number = self.ast_nodes.items[self_ast_node_index].line,
+                            .outer_decl = type_slot_index - 1,
+                        },
                     };
                     if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
                         for (paths.items) |resume_info| {