diff --git a/README.md b/README.md
index 397cf5641fe498f6e60778f6bc8438d61568f10c..a73f404552bee35dc5854533c07b147ca8830afd 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,11 @@ Run `ng generate component component-name` to generate a new component. You can
 
 ## Build
 
-Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
+Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. For example:
+
+    ng build --prod --base-href "/doc/"
+    rsync -avz dist/ server:doc
+
 
 ## Running unit tests
 
diff --git a/TODO b/TODO
index fba67dd966872212bb607ceb7db1fbf30a91961d..86d589680ba4ae0edb7ff05a9d6fb07531981a94 100644
--- a/TODO
+++ b/TODO
@@ -1,9 +1,9 @@
 ++ Add thrown type descriptions.
-++ Add structured production representation.
 ++ Make current member filter more noticeable.
 ++ Add class overview as default page.
    ++ Make the title be a link to the default page.
 ++ Add modifier information to non-attribute members (public, static, etc.).
+-- Add structured production representation.
 -- Add type hierarchy in type details.
     -- Add direct subtypes.
 -- Add declared-at info for types.
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 428066228a03745b694295b87451ef265046c175..e69849aa14f7831c19119abbdd5a8cb649cc6c9e 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -73,14 +73,6 @@ export class AppComponent implements OnInit {
     this.packageService.getPackages().then(packages => this.packages = packages);
   }
 
-  declaredAt(member: Member): string {
-    if (member.doc) {
-      return `${member.doc.ragFile}:${member.doc.line}`;
-    } else {
-      return "";
-    }
-  }
-
   filteredPackage(pkg: Package): boolean {
     var filter = this.filter.toLowerCase();
     for (var i = 0; i < pkg.groups.length; i++) {
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index f65502b76f463b8142d7f8f951321fd4ff8b6cd8..de1f12bced20396e560cbc9f5bfdec989ba13ace 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -13,6 +13,7 @@ import { StringFilterPipe } from './string-filter.pipe';
 import { SourceViewComponent } from './source-view/source-view.component';
 import { EditorDirective } from './editor.directive';
 import { DeclaredAtComponent } from './declared-at/declared-at.component';
+import { AstDeclComponent } from './ast-decl/ast-decl.component';
 
 @NgModule({
   imports:      [
@@ -40,6 +41,7 @@ import { DeclaredAtComponent } from './declared-at/declared-at.component';
     SourceViewComponent,
     EditorDirective,
     DeclaredAtComponent,
+    AstDeclComponent,
   ],
   bootstrap:    [ AppComponent ]
 })
diff --git a/src/app/ast-decl/ast-component.ts b/src/app/ast-decl/ast-component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c3e62dc082829726301de29e49a366a426534cb3
--- /dev/null
+++ b/src/app/ast-decl/ast-component.ts
@@ -0,0 +1,23 @@
+import {TypeRef} from '../type-ref';
+
+export class AstComponent {
+  name: string;
+  type: TypeRef;
+  kind: string;
+
+  static fromJson(json: any): AstComponent {
+    var name: string = undefined;
+    if (json.n) {
+      name = json.n as string;
+    }
+    var kind = "regular";
+    if (json.k) {
+      kind = json.k;
+    }
+    return {
+      name: json.n as string,
+      type: TypeRef.fromJson(json.e),
+      kind: kind,
+    };
+  }
+}
diff --git a/src/app/ast-decl/ast-decl.component.spec.ts b/src/app/ast-decl/ast-decl.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9a08ec2ec0f8f58b0d4c04fa99cac18106b0edb5
--- /dev/null
+++ b/src/app/ast-decl/ast-decl.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AstDeclComponent } from './ast-decl.component';
+
+describe('AstDeclComponent', () => {
+  let component: AstDeclComponent;
+  let fixture: ComponentFixture<AstDeclComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ AstDeclComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AstDeclComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/ast-decl/ast-decl.component.ts b/src/app/ast-decl/ast-decl.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9e7b3d7e15b5714be83f7f4b38c85fdff7432222
--- /dev/null
+++ b/src/app/ast-decl/ast-decl.component.ts
@@ -0,0 +1,51 @@
+import { Component, Input } from '@angular/core';
+
+import {Doc} from '../doc';
+import {TypeRef} from '../type-ref';
+import {AstDecl} from './ast-decl';
+
+@Component({
+  selector: 'ast-decl',
+  styles: [`
+    .ast-decl {
+      font-weight: bold;
+      padding-left: 3em;
+    }
+    .ast-component {
+      padding-left: 4em;
+    }
+  `],
+  template: `
+  <p *ngIf="_decl">JastAdd production: <br>
+    <div class="ast-decl">{{_decl.name}}: <type-ref [type]="_decl.extends"></type-ref><!--
+    --><ng-container *ngIf="_decl.components"> ::= <!--
+      --><ng-container *ngFor="let comp of _decl.components"><!--
+        --><div class="ast-component"><!--
+        --><ng-container *ngIf="comp.kind == 'regular'"><!--
+          --><ng-container *ngIf="comp.name">{{comp.name}}:</ng-container><type-ref [type]="comp.type"></type-ref> <!--
+        --></ng-container><!--
+        --><ng-container *ngIf="comp.kind == 'list'"><!--
+          --><ng-container *ngIf="comp.name">{{comp.name}}:</ng-container><type-ref [type]="comp.type"></type-ref>* <!--
+        --></ng-container><!--
+        --><ng-container *ngIf="comp.kind == 'opt'"><!--
+          -->[<ng-container *ngIf="comp.name">{{comp.name}}:</ng-container><type-ref [type]="comp.type"></type-ref>] <!--
+        --></ng-container><!--
+        --><ng-container *ngIf="comp.kind == 'token'"><!--
+          -->&lt;<ng-container *ngIf="comp.name">{{comp.name}}:</ng-container><type-ref [type]="comp.type"></type-ref>&gt; <!--
+        --></ng-container><!--
+        --></div><!--
+      --></ng-container><!--
+    --></ng-container>
+    </div>
+  `,
+})
+export class AstDeclComponent {
+  private _decl: AstDecl;
+
+  constructor() { }
+
+  @Input()
+  set decl(decl: AstDecl) {
+    this._decl = decl;
+  }
+}
diff --git a/src/app/ast-decl/ast-decl.ts b/src/app/ast-decl/ast-decl.ts
new file mode 100644
index 0000000000000000000000000000000000000000..46c476d0be62ee94e25b0a84f0f31b6507960b34
--- /dev/null
+++ b/src/app/ast-decl/ast-decl.ts
@@ -0,0 +1,27 @@
+import {TypeRef} from '../type-ref';
+import {AstComponent} from './ast-component';
+
+export class AstDecl {
+  name: string;
+  extends: TypeRef;
+  components?: AstComponent[];
+
+  static fromJson(json: any): AstDecl {
+    if (!json) {
+      return undefined;
+    }
+    var ext: TypeRef = undefined
+    if (json.e) {
+      ext = TypeRef.fromJson(json.e)
+    }
+    var components: AstComponent[] = undefined;
+    if (json.c) {
+      components = (json.c as any[]).map(c => AstComponent.fromJson(c));
+    }
+    return {
+      name: json.n as string,
+      extends: ext,
+      components: components,
+    };
+  }
+}
diff --git a/src/app/doc.ts b/src/app/doc.ts
index d201353965df8dd94cd7693a2c7bebea9538d5b0..61e60baceede82afc01e16e80fee4072271e7063 100644
--- a/src/app/doc.ts
+++ b/src/app/doc.ts
@@ -1,26 +1,27 @@
+import {AstDecl} from './ast-decl/ast-decl';
+
 export class Doc {
   ast: string;
+  astdecl: AstDecl;
   ragFile: string;
   line: number;
   description: string;
   apilevel: string;
   params: string[]
 
-  paramDesc(name: string): string {
-    if (this.params) {
-      for (var i = 0; i < this.params.length; i++) {
-        var param = this.params[i];
-        var index = param.indexOf(' ');
-        if (index >= 0 && param.substring(0, index) === name) {
-          return ' : ' + param.substring(index + 1);
-        }
-      }
-    }
-    return '';
-  }
-
   static fromJson(json: any): Doc {
-    var obj = Object.create(Doc.prototype);
-    return Object.assign(obj, json);
+    var astdecl: AstDecl = undefined;
+    if (json.astdecl) {
+      astdecl = AstDecl.fromJson(json.astdecl);
+    }
+    return {
+      ast: json.ast,
+      astdecl: astdecl,
+      ragFile: json.ragFile,
+      line: json.line,
+      description: json.description,
+      apilevel: json.apilevel,
+      params: json.params,
+    };
   }
 }
diff --git a/src/app/type-details.component.html b/src/app/type-details.component.html
index 6a8b39ed72ec065eb2cd6230862cc594cb8f411e..dd431b9ccce3ce4cba63fbff20a78909f260b756 100644
--- a/src/app/type-details.component.html
+++ b/src/app/type-details.component.html
@@ -9,9 +9,9 @@
   <div *ngIf="type.doc">
     <p [innerHTML]="type.doc.description">
 
-    <p *ngIf="type.doc.astdecl">JastAdd production: <b>{{type.doc.astdecl}}</b>
+    <p *ngIf="type.doc.astdecl"><ast-decl [decl]="type.doc.astdecl"></ast-decl>
 
-    <p *ngIf="type.doc && type.doc.ragFile"><declared-at [doc]="type.doc"></declared-at>
+    <p *ngIf="type.doc.ragFile"><declared-at [doc]="type.doc"></declared-at>
   </div>
   <div class="filter">
     <input [(ngModel)]="filter" placeholder="Filter members...">
diff --git a/src/app/type-details.component.ts b/src/app/type-details.component.ts
index 3d54cd6e1a221c37995b2ab3da865d1010fc234e..3154a0ff2c14e1550704c36c0b1d44743592bc1b 100644
--- a/src/app/type-details.component.ts
+++ b/src/app/type-details.component.ts
@@ -8,7 +8,7 @@ import { MemberFilterService } from './member-filter.service';
 import { SelectionService } from './selection.service';
 import { Member } from './member';
 import { InheritedMembers } from './inherited-members';
-import {Doc} from './doc';
+import { Doc } from './doc';
 import { Parameter } from './parameter';
 
 import { ActivatedRoute, Params } from '@angular/router';
@@ -47,13 +47,15 @@ export class TypeDetailsComponent  implements OnInit {
     });
   }
 
-  declaredAt(doc: Doc): string {
-    return `${doc.ragFile}:${doc.line}`;
-  }
-
   paramDesc(doc: Doc, name: string): string {
-    if (doc) {
-      return doc.paramDesc(name);
+    if (doc.params) {
+      for (var i = 0; i < doc.params.length; i++) {
+        var param = doc.params[i];
+        var index = param.indexOf(' ');
+        if (index >= 0 && param.substring(0, index) === name) {
+          return ' : ' + param.substring(index + 1);
+        }
+      }
     }
     return '';
   }
diff --git a/src/app/type.ts b/src/app/type.ts
index 8b7313903a081b44838220fda4e10e6e9cb0fbd5..c7c794bc2bd1531cc725fb6dc194c0aa8e3a4998 100644
--- a/src/app/type.ts
+++ b/src/app/type.ts
@@ -4,11 +4,11 @@ import {TypeRef} from './type-ref';
 import {InheritedMembers} from './inherited-members';
 
 export class Type {
+  id: string;
   kind: string;
   name: string;
   pkg: string;
   mods: string[];
-  id: string;
   doc: Doc;
   groups: { [id: string] : Member[]; };
   args: TypeRef[]; // Type arguments.
@@ -20,6 +20,10 @@ export class Type {
   subtypes: TypeRef[];
 
   static fromJson(json: any): Type {
+    var doc: Doc = undefined;
+    if (json.doc) {
+      doc = Doc.fromJson(json.doc);
+    }
     var groups = {};
     if (json.groups) {
       for (var i = 0; i < json.groups.length; i++) {
@@ -33,7 +37,7 @@ export class Type {
     if (json.superclass) {
       superclass = TypeRef.fromJson(json.superclass);
     }
-    var superinterfaces: TypeRef[] = undefined;
+    var superinterfaces: TypeRef[] = [];
     if (json.superinterfaces) {
       superinterfaces = (json.superinterfaces as TypeRef[]).map(TypeRef.fromJson);
     }
@@ -60,16 +64,22 @@ export class Type {
     if (json.subtypes) {
       subtypes = (json.subtypes as any[]).map(arg => TypeRef.fromJson(arg));
     }
-    return Object.assign({}, json, {
-      groups: groups,
+    return {
       id: TypeRef.typeId(json.name, json.id),
+      kind: json.kind,
+      name: json.name,
+      pkg: json.pkg,
+      mods: json.mods as string[],
+      doc: doc,
+      groups: groups,
+      args: args,
       superclass: superclass,
       superinterfaces: superinterfaces,
       inherited_methods: inherited_methods,
       inherited_attributes: inherited_attributes,
       inherited_fields: inherited_fields,
       subtypes: subtypes,
-    });
+    };
   }
 }