Add a new protobuf codec for info data (#35)

Add a new protobuf codec for dart2js info.

Currently only supports conversion from Info to protobuf, and not in
reverse. This is intended to make writing analysis tools in other
languages significantly easier.
diff --git a/bin/info_json_to_proto.dart b/bin/info_json_to_proto.dart
new file mode 100644
index 0000000..28aad13
--- /dev/null
+++ b/bin/info_json_to_proto.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Command-line tool to convert an info.json file ouputted by dart2js to the
+/// alternative protobuf format.
+
+import 'dart:io';
+
+import 'package:dart2js_info/proto_info_codec.dart';
+import 'package:dart2js_info/src/util.dart';
+
+main(args) async {
+  if (args.length != 2) {
+    print('usage: dart tool/info_json_to_proto.dart '
+        'path-to-info.json path-to-info.pb');
+    exit(1);
+  }
+
+  final info = await infoFromFile(args.first);
+  final proto = new AllInfoProtoCodec().encode(info);
+  final outputFile = new File(args.last);
+  await outputFile.writeAsBytes(proto.writeToBuffer(), mode: FileMode.write);
+}
diff --git a/info.proto b/info.proto
new file mode 100644
index 0000000..38efc5c
--- /dev/null
+++ b/info.proto
@@ -0,0 +1,265 @@
+syntax = "proto3";
+
+package dart2js_info.proto;
+
+message DependencyInfoPB {
+  /** The dependency element's serialized_id, references as FunctionInfo or FieldInfo. */
+  string target_id = 1;
+
+  /** Either a selector mask indicating how this is used, or 'inlined'. */
+  string mask = 2;
+}
+
+/** The entire information produced when compiling a program. */
+message AllInfoPB {
+  /** Summary information about the program. */
+  ProgramInfoPB program = 1;
+
+  /** All the recorded information about elements processed by the compiler. */
+  map<string, InfoPB> all_infos = 2;
+}
+
+/*
+ * Common interface to many pieces of information generated by the dart2js
+ * compiler that are directly associated with an element (compilation unit,
+ * library, class, function, or field).
+ */
+message InfoPB {
+  /** Name of the element associated with this info. */
+  string name = 1;
+
+  /** An id to uniquely identify this info among infos of the same kind. */
+  int32 id = 2;
+
+  /** A globally unique id which combines kind and id together. */
+  string serialized_id = 3;
+
+  /** Id used by the compiler when instrumenting code for code coverage. */
+  string coverage_id = 4;
+
+  /** Bytes used in the generated code for the corresponding element. */
+  int32 size = 5;
+
+  /** The serialized_id of the enclosing element. */
+  string parent_id = 6;
+
+  /** How does this function or field depend on others. */
+  repeated DependencyInfoPB uses = 7;
+
+  /** Reserved tags for future common fields. */
+  reserved 8 to 99;
+
+  /** The concrete info type. */
+  oneof concrete {
+    /** Information about a library element. */
+    LibraryInfoPB library_info = 100;
+
+    /** Information about a class element. */
+    ClassInfoPB class_info = 101;
+
+    /** Information about a function element. */
+    FunctionInfoPB function_info = 102;
+
+    /** Information about a field element. */
+    FieldInfoPB field_info = 103;
+
+    /** Information about a constant element. */
+    ConstantInfoPB constant_info = 104;
+
+    /** Information about an output unit element. */
+    OutputUnitInfoPB output_unit_info = 105;
+
+    /** Information about a typedef element. */
+    TypedefInfoPB typedef_info = 106;
+
+    /** Information about a closure element. */
+    ClosureInfoPB closure_info = 107;
+  }
+}
+
+/** General metadata about the dart2js invocation. */
+message ProgramInfoPB {
+  /** serialized_id for the entrypoint FunctionInfo. */
+  string entrypoint_id = 1;
+
+  /** The overall size of the dart2js binary. */
+  int32 size = 2;
+
+  /** The version of dart2js used to compile the program. */
+  string dart2js_version = 3;
+
+  /** The time at which the compilation was performed in microseconds since epoch. */
+  int64 compilation_moment = 4;
+
+  /** The amount of time spent compiling the program in microseconds. */
+  int64 compilation_duration = 5;
+
+  /** The amount of time spent converting the info to protobuf in microseconds. */
+  int64 to_proto_duration = 6;
+  
+  /** The amount of time spent writing out the serialized info in microseconds. */
+  int64 dump_info_duration = 7;
+
+  /** true if noSuchMethod is used. */
+  bool no_such_method_enabled = 8;
+
+  /** True if Object.runtimeType is used. */
+  bool is_runtime_type_used = 9;
+
+  /** True if dart:isolate library is used. */
+  bool is_isolate_used = 10;
+
+  /** True if Function.apply is used. */
+  bool is_function_apply_used = 11;
+
+  /** True if dart:mirrors features are used. */
+  bool is_mirrors_used = 12;
+
+  /** Whether the resulting dart2js binary is minified. */
+  bool minified = 13;
+}
+
+/** Info associated with a library element. */
+message LibraryInfoPB {
+  /** The canonical uri that identifies the library. */
+  string uri = 1;
+
+  /** The serialized_ids of all FunctionInfo, FieldInfo, ClassInfo and TypedefInfo elements that are defined in the library. */
+  repeated string children_ids = 2;
+}
+
+/**
+ * Information about an output unit. Normally there is just one for the entire
+ * program unless the application uses deferred imports, in which case there
+ * would be an additional output unit per deferred chunk.
+ */
+message OutputUnitInfoPB {
+  /** The deferred imports that will load this output unit. */
+  repeated string imports = 1;
+}
+
+/** Information about a class element. */
+message ClassInfoPB {
+  /** Whether the class is abstract. */
+  bool is_abstract = 1;
+
+  /** The serialized_ids of all FunctionInfo and FieldInfo elements defined in the class. */
+  repeated string children_ids = 2;
+}
+
+
+/** Information about a constant value. */
+message ConstantInfoPB {
+  /** The actual generated code for the constant. */
+  string code = 1;
+}
+
+/** Information about a field element. */
+message FieldInfoPB {
+  /** The type of the field. */
+  string type = 1;
+
+  /** The type inferred by dart2js's whole program analysis. */
+  string inferred_type = 2;
+
+  /** The serialized_ids of all ClosureInfo elements nested in the field initializer. */
+  repeated string children_ids = 3;
+
+  /** The actual generated code for the field. */
+  string code = 4;
+
+  /** Whether the field is a const declaration. */
+  bool is_const = 5;
+
+  /** When isConst is true, the serialized_id of the ConstantInfo initializer expression. */
+  string initializer_id = 6;
+}
+
+/** Information about a typedef declaration. */
+message TypedefInfoPB {
+  /** The declared type. */
+  string type = 1;
+}
+
+/** Available function modifiers. */
+message FunctionModifiersPB {
+  /** Whether the function is declared as static. */
+  bool is_static = 1;
+
+  /** Whether the function is declared as const. */
+  bool is_const = 2;
+
+  /** Whether the function is a factory constructor. */
+  bool is_factory = 3;
+
+  /** Whether the function is declared as extern. */
+  bool is_external = 4;
+}
+
+/** Information about a function parameter. */
+message ParameterInfoPB {
+  string name = 1;
+  string type = 2;
+  string declared_type = 3;
+}
+
+/**
+ * A measurement entry (practically a source-span location where the
+ * measurement was seen).
+ */
+message MeasurementEntryPB {
+  string name = 1;
+  repeated int32 values = 2;
+}
+
+/** A scalar measurement. */
+message MeasurementCounterPB {
+  string name = 1;
+  int32 value = 2;
+}
+
+/**
+ * A collection of data points for each metric. Used to summarize a single
+ * function, a library, a package, or an entire program.
+ */
+message MeasurementsPB {
+  string source_file = 1;
+  repeated MeasurementEntryPB entries = 2;
+  repeated MeasurementCounterPB counters = 3;
+}
+
+/** Information about a function or method. */
+message FunctionInfoPB {
+  /** Modifiers applied to the function. */
+  FunctionModifiersPB function_modifiers = 1;
+
+  /** serialized_ids of any ClosureInfo elements declared in the function. */
+  repeated string children_ids = 2;
+
+  /** The declared return type. */
+  string return_type = 3;
+
+  /** The inferred return type. */
+  string inferred_return_type = 4;
+
+  /** Name and type information for each parameter. */
+  repeated ParameterInfoPB parameters = 5;
+
+  /** Side-effects of the function. */
+  string side_effects = 6;
+
+  /** How many function calls were inlined into the function. */
+  int32 inlined_count = 7;
+
+  /** The actual generated code. */
+  string code = 8;
+
+  /** Measurements collected for this function. */
+  MeasurementsPB measurements = 9;
+}
+
+/** Information about a closure, also known as a local function. */
+message ClosureInfoPB {
+  /** serialized_id of the FunctionInfo wrapped by this closure. */
+  string function_id = 1;
+}
diff --git a/lib/proto_info_codec.dart b/lib/proto_info_codec.dart
new file mode 100644
index 0000000..bc17e41
--- /dev/null
+++ b/lib/proto_info_codec.dart
@@ -0,0 +1,265 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Converters and codecs for converting between Protobuf and [Info] classes.
+
+import 'dart:convert';
+import 'package:fixnum/fixnum.dart';
+
+import 'info.dart';
+import 'src/proto/info.pb.dart';
+
+export 'src/proto/info.pb.dart';
+
+class ProtoToAllInfoConverter extends Converter<AllInfoPB, AllInfo> {
+  AllInfo convert(AllInfoPB info) {
+    // TODO(lorenvs): Implement this conversion. It is unlikely to to be used
+    // by production code since the goal of the proto codec is to consume this
+    // information from other languages. However, it is useful for roundtrip
+    // testing, so we should support it.
+    throw new UnimplementedError('ProtoToAllInfoConverter is not implemented');
+  }
+}
+
+class AllInfoToProtoConverter extends Converter<AllInfo, AllInfoPB> {
+  AllInfoPB convert(AllInfo info) => _convertToAllInfoPB(info);
+
+  static DependencyInfoPB _convertToDependencyInfoPB(DependencyInfo info) {
+    return new DependencyInfoPB()
+      ..targetId = info.target?.serializedId
+      ..mask = info.mask;
+  }
+
+  static ParameterInfoPB _convertToParameterInfoPB(ParameterInfo info) {
+    return new ParameterInfoPB()
+      ..name = info.name
+      ..type = info.type
+      ..declaredType = info.declaredType;
+  }
+
+  static MeasurementsPB _convertToMeasurementsPB(Measurements measurements) {
+    final proto = new MeasurementsPB();
+
+    if (measurements.uri != null) {
+      proto.sourceFile = measurements.uri.toString();
+    }
+
+    measurements.entries.forEach((metric, values) {
+      final entryProto = new MeasurementEntryPB()..name = metric.name;
+
+      for (final entry in values) {
+        entryProto.values.add(entry.begin);
+        entryProto.values.add(entry.end);
+      }
+
+      proto.entries.add(entryProto);
+    });
+
+    measurements.counters.forEach((metric, value) {
+      proto.counters.add(new MeasurementCounterPB()
+        ..name = metric.name
+        ..value = value);
+    });
+
+    return proto;
+  }
+
+  static LibraryInfoPB _convertToLibraryInfoPB(LibraryInfo info) {
+    final proto = new LibraryInfoPB()..uri = info.uri.toString();
+
+    proto.childrenIds
+        .addAll(info.topLevelFunctions.map((func) => func.serializedId));
+    proto.childrenIds
+        .addAll(info.topLevelVariables.map((field) => field.serializedId));
+    proto.childrenIds.addAll(info.classes.map((clazz) => clazz.serializedId));
+    proto.childrenIds.addAll(info.typedefs.map((def) => def.serializedId));
+
+    return proto;
+  }
+
+  static ClassInfoPB _convertToClassInfoPB(ClassInfo info) {
+    final proto = new ClassInfoPB()..isAbstract = info.isAbstract;
+
+    proto.childrenIds.addAll(info.functions.map((func) => func.serializedId));
+    proto.childrenIds.addAll(info.fields.map((field) => field.serializedId));
+
+    return proto;
+  }
+
+  static FunctionModifiersPB _convertToFunctionModifiers(
+      FunctionModifiers modifiers) {
+    return new FunctionModifiersPB()
+      ..isStatic = modifiers.isStatic
+      ..isConst = modifiers.isConst
+      ..isFactory = modifiers.isFactory
+      ..isExternal = modifiers.isExternal;
+  }
+
+  static FunctionInfoPB _convertToFunctionInfoPB(FunctionInfo info) {
+    final proto = new FunctionInfoPB()
+      ..functionModifiers = _convertToFunctionModifiers(info.modifiers)
+      ..inlinedCount = info.inlinedCount ?? 0;
+
+    if (info.returnType != null) {
+      proto.returnType = info.returnType;
+    }
+
+    if (info.inferredReturnType != null) {
+      proto.inferredReturnType = info.inferredReturnType;
+    }
+
+    if (info.code != null) {
+      proto.code = info.code;
+    }
+
+    if (info.sideEffects != null) {
+      proto.sideEffects = info.sideEffects;
+    }
+
+    if (info.measurements != null) {
+      proto.measurements = _convertToMeasurementsPB(info.measurements);
+    }
+
+    proto.childrenIds
+        .addAll(info.closures.map(((closure) => closure.serializedId)));
+    proto.parameters.addAll(info.parameters.map(_convertToParameterInfoPB));
+
+    return proto;
+  }
+
+  static FieldInfoPB _convertToFieldInfoPB(FieldInfo info) {
+    final proto = new FieldInfoPB()
+      ..type = info.type
+      ..inferredType = info.inferredType
+      ..isConst = info.isConst;
+
+    if (info.code != null) {
+      proto.code = info.code;
+    }
+
+    if (info.initializer != null) {
+      proto.initializerId = info.initializer.serializedId;
+    }
+
+    proto.childrenIds
+        .addAll(info.closures.map((closure) => closure.serializedId));
+
+    return proto;
+  }
+
+  static ConstantInfoPB _convertToConstantInfoPB(ConstantInfo info) {
+    return new ConstantInfoPB()..code = info.code;
+  }
+
+  static OutputUnitInfoPB _convertToOutputUnitInfoPB(OutputUnitInfo info) {
+    final proto = new OutputUnitInfoPB();
+    proto.imports.addAll(info.imports.where((import) => import != null));
+    return proto;
+  }
+
+  static TypedefInfoPB _convertToTypedefInfoPB(TypedefInfo info) {
+    return new TypedefInfoPB()..type = info.type;
+  }
+
+  static ClosureInfoPB _convertToClosureInfoPB(ClosureInfo info) {
+    return new ClosureInfoPB()..functionId = info.function.serializedId;
+  }
+
+  static InfoPB _convertToInfoPB(Info info) {
+    final proto = new InfoPB()
+      ..id = info.id
+      ..serializedId = info.serializedId
+      ..size = info.size;
+
+    if (info.name != null) {
+      proto.name = info.name;
+    }
+
+    if (info.parent != null) {
+      proto.parentId = info.parent.serializedId;
+    }
+
+    if (info.coverageId != null) {
+      proto.coverageId = info.coverageId;
+    }
+
+    if (info is CodeInfo) {
+      proto.uses.addAll(info.uses.map(_convertToDependencyInfoPB));
+    }
+
+    if (info is LibraryInfo) {
+      proto.libraryInfo = _convertToLibraryInfoPB(info);
+    } else if (info is ClassInfo) {
+      proto.classInfo = _convertToClassInfoPB(info);
+    } else if (info is FunctionInfo) {
+      proto.functionInfo = _convertToFunctionInfoPB(info);
+    } else if (info is FieldInfo) {
+      proto.fieldInfo = _convertToFieldInfoPB(info);
+    } else if (info is ConstantInfo) {
+      proto.constantInfo = _convertToConstantInfoPB(info);
+    } else if (info is OutputUnitInfo) {
+      proto.outputUnitInfo = _convertToOutputUnitInfoPB(info);
+    } else if (info is TypedefInfo) {
+      proto.typedefInfo = _convertToTypedefInfoPB(info);
+    } else if (info is ClosureInfo) {
+      proto.closureInfo = _convertToClosureInfoPB(info);
+    }
+
+    return proto;
+  }
+
+  static ProgramInfoPB _convertToProgramInfoPB(ProgramInfo info) {
+    return new ProgramInfoPB()
+      ..entrypointId = info.entrypoint.serializedId
+      ..size = info.size
+      ..dart2jsVersion = info.dart2jsVersion
+      ..compilationMoment =
+          new Int64(info.compilationMoment.microsecondsSinceEpoch)
+      ..compilationDuration = new Int64(info.compilationDuration.inMicroseconds)
+      ..toProtoDuration = new Int64(info.toJsonDuration.inMicroseconds)
+      ..dumpInfoDuration = new Int64(info.dumpInfoDuration.inMicroseconds)
+      ..noSuchMethodEnabled = info.noSuchMethodEnabled ?? false
+      ..isRuntimeTypeUsed = info.isRuntimeTypeUsed ?? false
+      ..isIsolateUsed = info.isIsolateInUse ?? false
+      ..isFunctionApplyUsed = info.isFunctionApplyUsed ?? false
+      ..isMirrorsUsed = info.isMirrorsUsed ?? false
+      ..minified = info.minified ?? false;
+  }
+
+  static Iterable<AllInfoPB_AllInfosEntry>
+      _convertToAllInfosEntries<T extends Info>(Iterable<T> infos) sync* {
+    for (final info in infos) {
+      final infoProto = _convertToInfoPB(info);
+      final entry = new AllInfoPB_AllInfosEntry()
+        ..key = infoProto.serializedId
+        ..value = infoProto;
+      yield entry;
+    }
+  }
+
+  static AllInfoPB _convertToAllInfoPB(AllInfo info) {
+    final proto = new AllInfoPB()
+      ..program = _convertToProgramInfoPB(info.program);
+
+    proto.allInfos.addAll(_convertToAllInfosEntries(info.libraries));
+    proto.allInfos.addAll(_convertToAllInfosEntries(info.classes));
+    proto.allInfos.addAll(_convertToAllInfosEntries(info.functions));
+    proto.allInfos.addAll(_convertToAllInfosEntries(info.fields));
+    proto.allInfos.addAll(_convertToAllInfosEntries(info.constants));
+    proto.allInfos.addAll(_convertToAllInfosEntries(info.outputUnits));
+    proto.allInfos.addAll(_convertToAllInfosEntries(info.typedefs));
+    proto.allInfos.addAll(_convertToAllInfosEntries(info.closures));
+
+    return proto;
+  }
+}
+
+/// A codec for converting [AllInfo] to a protobuf format.
+///
+/// This codec is still experimental, and will likely crash on certain output
+/// from dart2js.
+class AllInfoProtoCodec extends Codec<AllInfo, AllInfoPB> {
+  final Converter<AllInfo, AllInfoPB> encoder = new AllInfoToProtoConverter();
+  final Converter<AllInfoPB, AllInfo> decoder = new ProtoToAllInfoConverter();
+}
diff --git a/lib/src/proto/info.pb.dart b/lib/src/proto/info.pb.dart
new file mode 100644
index 0000000..b506bda
--- /dev/null
+++ b/lib/src/proto/info.pb.dart
@@ -0,0 +1,1140 @@
+///
+//  Generated code. Do not modify.
+///
+// ignore_for_file: non_constant_identifier_names,library_prefixes
+
+// ignore: UNUSED_SHOWN_NAME
+import 'dart:core' show int, bool, double, String, List, override;
+
+import 'package:fixnum/fixnum.dart';
+import 'package:protobuf/protobuf.dart';
+
+class DependencyInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('DependencyInfoPB')
+    ..aOS(1, 'targetId')
+    ..aOS(2, 'mask')
+    ..hasRequiredFields = false;
+
+  DependencyInfoPB() : super();
+  DependencyInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  DependencyInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  DependencyInfoPB clone() => new DependencyInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static DependencyInfoPB create() => new DependencyInfoPB();
+  static PbList<DependencyInfoPB> createRepeated() =>
+      new PbList<DependencyInfoPB>();
+  static DependencyInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyDependencyInfoPB();
+    return _defaultInstance;
+  }
+
+  static DependencyInfoPB _defaultInstance;
+  static void $checkItem(DependencyInfoPB v) {
+    if (v is! DependencyInfoPB) checkItemFailed(v, 'DependencyInfoPB');
+  }
+
+  String get targetId => $_getS(0, '');
+  set targetId(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasTargetId() => $_has(0);
+  void clearTargetId() => clearField(1);
+
+  String get mask => $_getS(1, '');
+  set mask(String v) {
+    $_setString(1, v);
+  }
+
+  bool hasMask() => $_has(1);
+  void clearMask() => clearField(2);
+}
+
+class _ReadonlyDependencyInfoPB extends DependencyInfoPB
+    with ReadonlyMessageMixin {}
+
+class AllInfoPB_AllInfosEntry extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('AllInfoPB_AllInfosEntry')
+    ..aOS(1, 'key')
+    ..a<InfoPB>(2, 'value', PbFieldType.OM, InfoPB.getDefault, InfoPB.create)
+    ..hasRequiredFields = false;
+
+  AllInfoPB_AllInfosEntry() : super();
+  AllInfoPB_AllInfosEntry.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  AllInfoPB_AllInfosEntry.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  AllInfoPB_AllInfosEntry clone() =>
+      new AllInfoPB_AllInfosEntry()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static AllInfoPB_AllInfosEntry create() => new AllInfoPB_AllInfosEntry();
+  static PbList<AllInfoPB_AllInfosEntry> createRepeated() =>
+      new PbList<AllInfoPB_AllInfosEntry>();
+  static AllInfoPB_AllInfosEntry getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyAllInfoPB_AllInfosEntry();
+    return _defaultInstance;
+  }
+
+  static AllInfoPB_AllInfosEntry _defaultInstance;
+  static void $checkItem(AllInfoPB_AllInfosEntry v) {
+    if (v is! AllInfoPB_AllInfosEntry)
+      checkItemFailed(v, 'AllInfoPB_AllInfosEntry');
+  }
+
+  String get key => $_getS(0, '');
+  set key(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasKey() => $_has(0);
+  void clearKey() => clearField(1);
+
+  InfoPB get value => $_getN(1);
+  set value(InfoPB v) {
+    setField(2, v);
+  }
+
+  bool hasValue() => $_has(1);
+  void clearValue() => clearField(2);
+}
+
+class _ReadonlyAllInfoPB_AllInfosEntry extends AllInfoPB_AllInfosEntry
+    with ReadonlyMessageMixin {}
+
+class AllInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('AllInfoPB')
+    ..a<ProgramInfoPB>(1, 'program', PbFieldType.OM, ProgramInfoPB.getDefault,
+        ProgramInfoPB.create)
+    ..pp<AllInfoPB_AllInfosEntry>(2, 'allInfos', PbFieldType.PM,
+        AllInfoPB_AllInfosEntry.$checkItem, AllInfoPB_AllInfosEntry.create)
+    ..hasRequiredFields = false;
+
+  AllInfoPB() : super();
+  AllInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  AllInfoPB.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  AllInfoPB clone() => new AllInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static AllInfoPB create() => new AllInfoPB();
+  static PbList<AllInfoPB> createRepeated() => new PbList<AllInfoPB>();
+  static AllInfoPB getDefault() {
+    if (_defaultInstance == null) _defaultInstance = new _ReadonlyAllInfoPB();
+    return _defaultInstance;
+  }
+
+  static AllInfoPB _defaultInstance;
+  static void $checkItem(AllInfoPB v) {
+    if (v is! AllInfoPB) checkItemFailed(v, 'AllInfoPB');
+  }
+
+  ProgramInfoPB get program => $_getN(0);
+  set program(ProgramInfoPB v) {
+    setField(1, v);
+  }
+
+  bool hasProgram() => $_has(0);
+  void clearProgram() => clearField(1);
+
+  List<AllInfoPB_AllInfosEntry> get allInfos => $_getList(1);
+}
+
+class _ReadonlyAllInfoPB extends AllInfoPB with ReadonlyMessageMixin {}
+
+class InfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('InfoPB')
+    ..aOS(1, 'name')
+    ..a<int>(2, 'id', PbFieldType.O3)
+    ..aOS(3, 'serializedId')
+    ..aOS(4, 'coverageId')
+    ..a<int>(5, 'size', PbFieldType.O3)
+    ..aOS(6, 'parentId')
+    ..pp<DependencyInfoPB>(7, 'uses', PbFieldType.PM,
+        DependencyInfoPB.$checkItem, DependencyInfoPB.create)
+    ..a<LibraryInfoPB>(100, 'libraryInfo', PbFieldType.OM,
+        LibraryInfoPB.getDefault, LibraryInfoPB.create)
+    ..a<ClassInfoPB>(101, 'classInfo', PbFieldType.OM, ClassInfoPB.getDefault,
+        ClassInfoPB.create)
+    ..a<FunctionInfoPB>(102, 'functionInfo', PbFieldType.OM,
+        FunctionInfoPB.getDefault, FunctionInfoPB.create)
+    ..a<FieldInfoPB>(103, 'fieldInfo', PbFieldType.OM, FieldInfoPB.getDefault,
+        FieldInfoPB.create)
+    ..a<ConstantInfoPB>(104, 'constantInfo', PbFieldType.OM,
+        ConstantInfoPB.getDefault, ConstantInfoPB.create)
+    ..a<OutputUnitInfoPB>(105, 'outputUnitInfo', PbFieldType.OM,
+        OutputUnitInfoPB.getDefault, OutputUnitInfoPB.create)
+    ..a<TypedefInfoPB>(106, 'typedefInfo', PbFieldType.OM,
+        TypedefInfoPB.getDefault, TypedefInfoPB.create)
+    ..a<ClosureInfoPB>(107, 'closureInfo', PbFieldType.OM,
+        ClosureInfoPB.getDefault, ClosureInfoPB.create)
+    ..hasRequiredFields = false;
+
+  InfoPB() : super();
+  InfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  InfoPB.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  InfoPB clone() => new InfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static InfoPB create() => new InfoPB();
+  static PbList<InfoPB> createRepeated() => new PbList<InfoPB>();
+  static InfoPB getDefault() {
+    if (_defaultInstance == null) _defaultInstance = new _ReadonlyInfoPB();
+    return _defaultInstance;
+  }
+
+  static InfoPB _defaultInstance;
+  static void $checkItem(InfoPB v) {
+    if (v is! InfoPB) checkItemFailed(v, 'InfoPB');
+  }
+
+  String get name => $_getS(0, '');
+  set name(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasName() => $_has(0);
+  void clearName() => clearField(1);
+
+  int get id => $_get(1, 0);
+  set id(int v) {
+    $_setSignedInt32(1, v);
+  }
+
+  bool hasId() => $_has(1);
+  void clearId() => clearField(2);
+
+  String get serializedId => $_getS(2, '');
+  set serializedId(String v) {
+    $_setString(2, v);
+  }
+
+  bool hasSerializedId() => $_has(2);
+  void clearSerializedId() => clearField(3);
+
+  String get coverageId => $_getS(3, '');
+  set coverageId(String v) {
+    $_setString(3, v);
+  }
+
+  bool hasCoverageId() => $_has(3);
+  void clearCoverageId() => clearField(4);
+
+  int get size => $_get(4, 0);
+  set size(int v) {
+    $_setSignedInt32(4, v);
+  }
+
+  bool hasSize() => $_has(4);
+  void clearSize() => clearField(5);
+
+  String get parentId => $_getS(5, '');
+  set parentId(String v) {
+    $_setString(5, v);
+  }
+
+  bool hasParentId() => $_has(5);
+  void clearParentId() => clearField(6);
+
+  List<DependencyInfoPB> get uses => $_getList(6);
+
+  LibraryInfoPB get libraryInfo => $_getN(7);
+  set libraryInfo(LibraryInfoPB v) {
+    setField(100, v);
+  }
+
+  bool hasLibraryInfo() => $_has(7);
+  void clearLibraryInfo() => clearField(100);
+
+  ClassInfoPB get classInfo => $_getN(8);
+  set classInfo(ClassInfoPB v) {
+    setField(101, v);
+  }
+
+  bool hasClassInfo() => $_has(8);
+  void clearClassInfo() => clearField(101);
+
+  FunctionInfoPB get functionInfo => $_getN(9);
+  set functionInfo(FunctionInfoPB v) {
+    setField(102, v);
+  }
+
+  bool hasFunctionInfo() => $_has(9);
+  void clearFunctionInfo() => clearField(102);
+
+  FieldInfoPB get fieldInfo => $_getN(10);
+  set fieldInfo(FieldInfoPB v) {
+    setField(103, v);
+  }
+
+  bool hasFieldInfo() => $_has(10);
+  void clearFieldInfo() => clearField(103);
+
+  ConstantInfoPB get constantInfo => $_getN(11);
+  set constantInfo(ConstantInfoPB v) {
+    setField(104, v);
+  }
+
+  bool hasConstantInfo() => $_has(11);
+  void clearConstantInfo() => clearField(104);
+
+  OutputUnitInfoPB get outputUnitInfo => $_getN(12);
+  set outputUnitInfo(OutputUnitInfoPB v) {
+    setField(105, v);
+  }
+
+  bool hasOutputUnitInfo() => $_has(12);
+  void clearOutputUnitInfo() => clearField(105);
+
+  TypedefInfoPB get typedefInfo => $_getN(13);
+  set typedefInfo(TypedefInfoPB v) {
+    setField(106, v);
+  }
+
+  bool hasTypedefInfo() => $_has(13);
+  void clearTypedefInfo() => clearField(106);
+
+  ClosureInfoPB get closureInfo => $_getN(14);
+  set closureInfo(ClosureInfoPB v) {
+    setField(107, v);
+  }
+
+  bool hasClosureInfo() => $_has(14);
+  void clearClosureInfo() => clearField(107);
+}
+
+class _ReadonlyInfoPB extends InfoPB with ReadonlyMessageMixin {}
+
+class ProgramInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('ProgramInfoPB')
+    ..aOS(1, 'entrypointId')
+    ..a<int>(2, 'size', PbFieldType.O3)
+    ..aOS(3, 'dart2jsVersion')
+    ..aInt64(4, 'compilationMoment')
+    ..aInt64(5, 'compilationDuration')
+    ..aInt64(6, 'toProtoDuration')
+    ..aInt64(7, 'dumpInfoDuration')
+    ..aOB(8, 'noSuchMethodEnabled')
+    ..aOB(9, 'isRuntimeTypeUsed')
+    ..aOB(10, 'isIsolateUsed')
+    ..aOB(11, 'isFunctionApplyUsed')
+    ..aOB(12, 'isMirrorsUsed')
+    ..aOB(13, 'minified')
+    ..hasRequiredFields = false;
+
+  ProgramInfoPB() : super();
+  ProgramInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  ProgramInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  ProgramInfoPB clone() => new ProgramInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static ProgramInfoPB create() => new ProgramInfoPB();
+  static PbList<ProgramInfoPB> createRepeated() => new PbList<ProgramInfoPB>();
+  static ProgramInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyProgramInfoPB();
+    return _defaultInstance;
+  }
+
+  static ProgramInfoPB _defaultInstance;
+  static void $checkItem(ProgramInfoPB v) {
+    if (v is! ProgramInfoPB) checkItemFailed(v, 'ProgramInfoPB');
+  }
+
+  String get entrypointId => $_getS(0, '');
+  set entrypointId(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasEntrypointId() => $_has(0);
+  void clearEntrypointId() => clearField(1);
+
+  int get size => $_get(1, 0);
+  set size(int v) {
+    $_setSignedInt32(1, v);
+  }
+
+  bool hasSize() => $_has(1);
+  void clearSize() => clearField(2);
+
+  String get dart2jsVersion => $_getS(2, '');
+  set dart2jsVersion(String v) {
+    $_setString(2, v);
+  }
+
+  bool hasDart2jsVersion() => $_has(2);
+  void clearDart2jsVersion() => clearField(3);
+
+  Int64 get compilationMoment => $_getI64(3);
+  set compilationMoment(Int64 v) {
+    $_setInt64(3, v);
+  }
+
+  bool hasCompilationMoment() => $_has(3);
+  void clearCompilationMoment() => clearField(4);
+
+  Int64 get compilationDuration => $_getI64(4);
+  set compilationDuration(Int64 v) {
+    $_setInt64(4, v);
+  }
+
+  bool hasCompilationDuration() => $_has(4);
+  void clearCompilationDuration() => clearField(5);
+
+  Int64 get toProtoDuration => $_getI64(5);
+  set toProtoDuration(Int64 v) {
+    $_setInt64(5, v);
+  }
+
+  bool hasToProtoDuration() => $_has(5);
+  void clearToProtoDuration() => clearField(6);
+
+  Int64 get dumpInfoDuration => $_getI64(6);
+  set dumpInfoDuration(Int64 v) {
+    $_setInt64(6, v);
+  }
+
+  bool hasDumpInfoDuration() => $_has(6);
+  void clearDumpInfoDuration() => clearField(7);
+
+  bool get noSuchMethodEnabled => $_get(7, false);
+  set noSuchMethodEnabled(bool v) {
+    $_setBool(7, v);
+  }
+
+  bool hasNoSuchMethodEnabled() => $_has(7);
+  void clearNoSuchMethodEnabled() => clearField(8);
+
+  bool get isRuntimeTypeUsed => $_get(8, false);
+  set isRuntimeTypeUsed(bool v) {
+    $_setBool(8, v);
+  }
+
+  bool hasIsRuntimeTypeUsed() => $_has(8);
+  void clearIsRuntimeTypeUsed() => clearField(9);
+
+  bool get isIsolateUsed => $_get(9, false);
+  set isIsolateUsed(bool v) {
+    $_setBool(9, v);
+  }
+
+  bool hasIsIsolateUsed() => $_has(9);
+  void clearIsIsolateUsed() => clearField(10);
+
+  bool get isFunctionApplyUsed => $_get(10, false);
+  set isFunctionApplyUsed(bool v) {
+    $_setBool(10, v);
+  }
+
+  bool hasIsFunctionApplyUsed() => $_has(10);
+  void clearIsFunctionApplyUsed() => clearField(11);
+
+  bool get isMirrorsUsed => $_get(11, false);
+  set isMirrorsUsed(bool v) {
+    $_setBool(11, v);
+  }
+
+  bool hasIsMirrorsUsed() => $_has(11);
+  void clearIsMirrorsUsed() => clearField(12);
+
+  bool get minified => $_get(12, false);
+  set minified(bool v) {
+    $_setBool(12, v);
+  }
+
+  bool hasMinified() => $_has(12);
+  void clearMinified() => clearField(13);
+}
+
+class _ReadonlyProgramInfoPB extends ProgramInfoPB with ReadonlyMessageMixin {}
+
+class LibraryInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('LibraryInfoPB')
+    ..aOS(1, 'uri')
+    ..pPS(2, 'childrenIds')
+    ..hasRequiredFields = false;
+
+  LibraryInfoPB() : super();
+  LibraryInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  LibraryInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  LibraryInfoPB clone() => new LibraryInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static LibraryInfoPB create() => new LibraryInfoPB();
+  static PbList<LibraryInfoPB> createRepeated() => new PbList<LibraryInfoPB>();
+  static LibraryInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyLibraryInfoPB();
+    return _defaultInstance;
+  }
+
+  static LibraryInfoPB _defaultInstance;
+  static void $checkItem(LibraryInfoPB v) {
+    if (v is! LibraryInfoPB) checkItemFailed(v, 'LibraryInfoPB');
+  }
+
+  String get uri => $_getS(0, '');
+  set uri(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasUri() => $_has(0);
+  void clearUri() => clearField(1);
+
+  List<String> get childrenIds => $_getList(1);
+}
+
+class _ReadonlyLibraryInfoPB extends LibraryInfoPB with ReadonlyMessageMixin {}
+
+class OutputUnitInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('OutputUnitInfoPB')
+    ..pPS(1, 'imports')
+    ..hasRequiredFields = false;
+
+  OutputUnitInfoPB() : super();
+  OutputUnitInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  OutputUnitInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  OutputUnitInfoPB clone() => new OutputUnitInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static OutputUnitInfoPB create() => new OutputUnitInfoPB();
+  static PbList<OutputUnitInfoPB> createRepeated() =>
+      new PbList<OutputUnitInfoPB>();
+  static OutputUnitInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyOutputUnitInfoPB();
+    return _defaultInstance;
+  }
+
+  static OutputUnitInfoPB _defaultInstance;
+  static void $checkItem(OutputUnitInfoPB v) {
+    if (v is! OutputUnitInfoPB) checkItemFailed(v, 'OutputUnitInfoPB');
+  }
+
+  List<String> get imports => $_getList(0);
+}
+
+class _ReadonlyOutputUnitInfoPB extends OutputUnitInfoPB
+    with ReadonlyMessageMixin {}
+
+class ClassInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('ClassInfoPB')
+    ..aOB(1, 'isAbstract')
+    ..pPS(2, 'childrenIds')
+    ..hasRequiredFields = false;
+
+  ClassInfoPB() : super();
+  ClassInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  ClassInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  ClassInfoPB clone() => new ClassInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static ClassInfoPB create() => new ClassInfoPB();
+  static PbList<ClassInfoPB> createRepeated() => new PbList<ClassInfoPB>();
+  static ClassInfoPB getDefault() {
+    if (_defaultInstance == null) _defaultInstance = new _ReadonlyClassInfoPB();
+    return _defaultInstance;
+  }
+
+  static ClassInfoPB _defaultInstance;
+  static void $checkItem(ClassInfoPB v) {
+    if (v is! ClassInfoPB) checkItemFailed(v, 'ClassInfoPB');
+  }
+
+  bool get isAbstract => $_get(0, false);
+  set isAbstract(bool v) {
+    $_setBool(0, v);
+  }
+
+  bool hasIsAbstract() => $_has(0);
+  void clearIsAbstract() => clearField(1);
+
+  List<String> get childrenIds => $_getList(1);
+}
+
+class _ReadonlyClassInfoPB extends ClassInfoPB with ReadonlyMessageMixin {}
+
+class ConstantInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('ConstantInfoPB')
+    ..aOS(1, 'code')
+    ..hasRequiredFields = false;
+
+  ConstantInfoPB() : super();
+  ConstantInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  ConstantInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  ConstantInfoPB clone() => new ConstantInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static ConstantInfoPB create() => new ConstantInfoPB();
+  static PbList<ConstantInfoPB> createRepeated() =>
+      new PbList<ConstantInfoPB>();
+  static ConstantInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyConstantInfoPB();
+    return _defaultInstance;
+  }
+
+  static ConstantInfoPB _defaultInstance;
+  static void $checkItem(ConstantInfoPB v) {
+    if (v is! ConstantInfoPB) checkItemFailed(v, 'ConstantInfoPB');
+  }
+
+  String get code => $_getS(0, '');
+  set code(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasCode() => $_has(0);
+  void clearCode() => clearField(1);
+}
+
+class _ReadonlyConstantInfoPB extends ConstantInfoPB with ReadonlyMessageMixin {
+}
+
+class FieldInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('FieldInfoPB')
+    ..aOS(1, 'type')
+    ..aOS(2, 'inferredType')
+    ..pPS(3, 'childrenIds')
+    ..aOS(4, 'code')
+    ..aOB(5, 'isConst')
+    ..aOS(6, 'initializerId')
+    ..hasRequiredFields = false;
+
+  FieldInfoPB() : super();
+  FieldInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  FieldInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  FieldInfoPB clone() => new FieldInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static FieldInfoPB create() => new FieldInfoPB();
+  static PbList<FieldInfoPB> createRepeated() => new PbList<FieldInfoPB>();
+  static FieldInfoPB getDefault() {
+    if (_defaultInstance == null) _defaultInstance = new _ReadonlyFieldInfoPB();
+    return _defaultInstance;
+  }
+
+  static FieldInfoPB _defaultInstance;
+  static void $checkItem(FieldInfoPB v) {
+    if (v is! FieldInfoPB) checkItemFailed(v, 'FieldInfoPB');
+  }
+
+  String get type => $_getS(0, '');
+  set type(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasType() => $_has(0);
+  void clearType() => clearField(1);
+
+  String get inferredType => $_getS(1, '');
+  set inferredType(String v) {
+    $_setString(1, v);
+  }
+
+  bool hasInferredType() => $_has(1);
+  void clearInferredType() => clearField(2);
+
+  List<String> get childrenIds => $_getList(2);
+
+  String get code => $_getS(3, '');
+  set code(String v) {
+    $_setString(3, v);
+  }
+
+  bool hasCode() => $_has(3);
+  void clearCode() => clearField(4);
+
+  bool get isConst => $_get(4, false);
+  set isConst(bool v) {
+    $_setBool(4, v);
+  }
+
+  bool hasIsConst() => $_has(4);
+  void clearIsConst() => clearField(5);
+
+  String get initializerId => $_getS(5, '');
+  set initializerId(String v) {
+    $_setString(5, v);
+  }
+
+  bool hasInitializerId() => $_has(5);
+  void clearInitializerId() => clearField(6);
+}
+
+class _ReadonlyFieldInfoPB extends FieldInfoPB with ReadonlyMessageMixin {}
+
+class TypedefInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('TypedefInfoPB')
+    ..aOS(1, 'type')
+    ..hasRequiredFields = false;
+
+  TypedefInfoPB() : super();
+  TypedefInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  TypedefInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  TypedefInfoPB clone() => new TypedefInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static TypedefInfoPB create() => new TypedefInfoPB();
+  static PbList<TypedefInfoPB> createRepeated() => new PbList<TypedefInfoPB>();
+  static TypedefInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyTypedefInfoPB();
+    return _defaultInstance;
+  }
+
+  static TypedefInfoPB _defaultInstance;
+  static void $checkItem(TypedefInfoPB v) {
+    if (v is! TypedefInfoPB) checkItemFailed(v, 'TypedefInfoPB');
+  }
+
+  String get type => $_getS(0, '');
+  set type(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasType() => $_has(0);
+  void clearType() => clearField(1);
+}
+
+class _ReadonlyTypedefInfoPB extends TypedefInfoPB with ReadonlyMessageMixin {}
+
+class FunctionModifiersPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('FunctionModifiersPB')
+    ..aOB(1, 'isStatic')
+    ..aOB(2, 'isConst')
+    ..aOB(3, 'isFactory')
+    ..aOB(4, 'isExternal')
+    ..hasRequiredFields = false;
+
+  FunctionModifiersPB() : super();
+  FunctionModifiersPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  FunctionModifiersPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  FunctionModifiersPB clone() =>
+      new FunctionModifiersPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static FunctionModifiersPB create() => new FunctionModifiersPB();
+  static PbList<FunctionModifiersPB> createRepeated() =>
+      new PbList<FunctionModifiersPB>();
+  static FunctionModifiersPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyFunctionModifiersPB();
+    return _defaultInstance;
+  }
+
+  static FunctionModifiersPB _defaultInstance;
+  static void $checkItem(FunctionModifiersPB v) {
+    if (v is! FunctionModifiersPB) checkItemFailed(v, 'FunctionModifiersPB');
+  }
+
+  bool get isStatic => $_get(0, false);
+  set isStatic(bool v) {
+    $_setBool(0, v);
+  }
+
+  bool hasIsStatic() => $_has(0);
+  void clearIsStatic() => clearField(1);
+
+  bool get isConst => $_get(1, false);
+  set isConst(bool v) {
+    $_setBool(1, v);
+  }
+
+  bool hasIsConst() => $_has(1);
+  void clearIsConst() => clearField(2);
+
+  bool get isFactory => $_get(2, false);
+  set isFactory(bool v) {
+    $_setBool(2, v);
+  }
+
+  bool hasIsFactory() => $_has(2);
+  void clearIsFactory() => clearField(3);
+
+  bool get isExternal => $_get(3, false);
+  set isExternal(bool v) {
+    $_setBool(3, v);
+  }
+
+  bool hasIsExternal() => $_has(3);
+  void clearIsExternal() => clearField(4);
+}
+
+class _ReadonlyFunctionModifiersPB extends FunctionModifiersPB
+    with ReadonlyMessageMixin {}
+
+class ParameterInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('ParameterInfoPB')
+    ..aOS(1, 'name')
+    ..aOS(2, 'type')
+    ..aOS(3, 'declaredType')
+    ..hasRequiredFields = false;
+
+  ParameterInfoPB() : super();
+  ParameterInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  ParameterInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  ParameterInfoPB clone() => new ParameterInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static ParameterInfoPB create() => new ParameterInfoPB();
+  static PbList<ParameterInfoPB> createRepeated() =>
+      new PbList<ParameterInfoPB>();
+  static ParameterInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyParameterInfoPB();
+    return _defaultInstance;
+  }
+
+  static ParameterInfoPB _defaultInstance;
+  static void $checkItem(ParameterInfoPB v) {
+    if (v is! ParameterInfoPB) checkItemFailed(v, 'ParameterInfoPB');
+  }
+
+  String get name => $_getS(0, '');
+  set name(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasName() => $_has(0);
+  void clearName() => clearField(1);
+
+  String get type => $_getS(1, '');
+  set type(String v) {
+    $_setString(1, v);
+  }
+
+  bool hasType() => $_has(1);
+  void clearType() => clearField(2);
+
+  String get declaredType => $_getS(2, '');
+  set declaredType(String v) {
+    $_setString(2, v);
+  }
+
+  bool hasDeclaredType() => $_has(2);
+  void clearDeclaredType() => clearField(3);
+}
+
+class _ReadonlyParameterInfoPB extends ParameterInfoPB
+    with ReadonlyMessageMixin {}
+
+class MeasurementEntryPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('MeasurementEntryPB')
+    ..aOS(1, 'name')
+    ..p<int>(2, 'values', PbFieldType.P3)
+    ..hasRequiredFields = false;
+
+  MeasurementEntryPB() : super();
+  MeasurementEntryPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  MeasurementEntryPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  MeasurementEntryPB clone() =>
+      new MeasurementEntryPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static MeasurementEntryPB create() => new MeasurementEntryPB();
+  static PbList<MeasurementEntryPB> createRepeated() =>
+      new PbList<MeasurementEntryPB>();
+  static MeasurementEntryPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyMeasurementEntryPB();
+    return _defaultInstance;
+  }
+
+  static MeasurementEntryPB _defaultInstance;
+  static void $checkItem(MeasurementEntryPB v) {
+    if (v is! MeasurementEntryPB) checkItemFailed(v, 'MeasurementEntryPB');
+  }
+
+  String get name => $_getS(0, '');
+  set name(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasName() => $_has(0);
+  void clearName() => clearField(1);
+
+  List<int> get values => $_getList(1);
+}
+
+class _ReadonlyMeasurementEntryPB extends MeasurementEntryPB
+    with ReadonlyMessageMixin {}
+
+class MeasurementCounterPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('MeasurementCounterPB')
+    ..aOS(1, 'name')
+    ..a<int>(2, 'value', PbFieldType.O3)
+    ..hasRequiredFields = false;
+
+  MeasurementCounterPB() : super();
+  MeasurementCounterPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  MeasurementCounterPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  MeasurementCounterPB clone() =>
+      new MeasurementCounterPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static MeasurementCounterPB create() => new MeasurementCounterPB();
+  static PbList<MeasurementCounterPB> createRepeated() =>
+      new PbList<MeasurementCounterPB>();
+  static MeasurementCounterPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyMeasurementCounterPB();
+    return _defaultInstance;
+  }
+
+  static MeasurementCounterPB _defaultInstance;
+  static void $checkItem(MeasurementCounterPB v) {
+    if (v is! MeasurementCounterPB) checkItemFailed(v, 'MeasurementCounterPB');
+  }
+
+  String get name => $_getS(0, '');
+  set name(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasName() => $_has(0);
+  void clearName() => clearField(1);
+
+  int get value => $_get(1, 0);
+  set value(int v) {
+    $_setSignedInt32(1, v);
+  }
+
+  bool hasValue() => $_has(1);
+  void clearValue() => clearField(2);
+}
+
+class _ReadonlyMeasurementCounterPB extends MeasurementCounterPB
+    with ReadonlyMessageMixin {}
+
+class MeasurementsPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('MeasurementsPB')
+    ..aOS(1, 'sourceFile')
+    ..pp<MeasurementEntryPB>(2, 'entries', PbFieldType.PM,
+        MeasurementEntryPB.$checkItem, MeasurementEntryPB.create)
+    ..pp<MeasurementCounterPB>(3, 'counters', PbFieldType.PM,
+        MeasurementCounterPB.$checkItem, MeasurementCounterPB.create)
+    ..hasRequiredFields = false;
+
+  MeasurementsPB() : super();
+  MeasurementsPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  MeasurementsPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  MeasurementsPB clone() => new MeasurementsPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static MeasurementsPB create() => new MeasurementsPB();
+  static PbList<MeasurementsPB> createRepeated() =>
+      new PbList<MeasurementsPB>();
+  static MeasurementsPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyMeasurementsPB();
+    return _defaultInstance;
+  }
+
+  static MeasurementsPB _defaultInstance;
+  static void $checkItem(MeasurementsPB v) {
+    if (v is! MeasurementsPB) checkItemFailed(v, 'MeasurementsPB');
+  }
+
+  String get sourceFile => $_getS(0, '');
+  set sourceFile(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasSourceFile() => $_has(0);
+  void clearSourceFile() => clearField(1);
+
+  List<MeasurementEntryPB> get entries => $_getList(1);
+
+  List<MeasurementCounterPB> get counters => $_getList(2);
+}
+
+class _ReadonlyMeasurementsPB extends MeasurementsPB with ReadonlyMessageMixin {
+}
+
+class FunctionInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('FunctionInfoPB')
+    ..a<FunctionModifiersPB>(1, 'functionModifiers', PbFieldType.OM,
+        FunctionModifiersPB.getDefault, FunctionModifiersPB.create)
+    ..pPS(2, 'childrenIds')
+    ..aOS(3, 'returnType')
+    ..aOS(4, 'inferredReturnType')
+    ..pp<ParameterInfoPB>(5, 'parameters', PbFieldType.PM,
+        ParameterInfoPB.$checkItem, ParameterInfoPB.create)
+    ..aOS(6, 'sideEffects')
+    ..a<int>(7, 'inlinedCount', PbFieldType.O3)
+    ..aOS(8, 'code')
+    ..a<MeasurementsPB>(9, 'measurements', PbFieldType.OM,
+        MeasurementsPB.getDefault, MeasurementsPB.create)
+    ..hasRequiredFields = false;
+
+  FunctionInfoPB() : super();
+  FunctionInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  FunctionInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  FunctionInfoPB clone() => new FunctionInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static FunctionInfoPB create() => new FunctionInfoPB();
+  static PbList<FunctionInfoPB> createRepeated() =>
+      new PbList<FunctionInfoPB>();
+  static FunctionInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyFunctionInfoPB();
+    return _defaultInstance;
+  }
+
+  static FunctionInfoPB _defaultInstance;
+  static void $checkItem(FunctionInfoPB v) {
+    if (v is! FunctionInfoPB) checkItemFailed(v, 'FunctionInfoPB');
+  }
+
+  FunctionModifiersPB get functionModifiers => $_getN(0);
+  set functionModifiers(FunctionModifiersPB v) {
+    setField(1, v);
+  }
+
+  bool hasFunctionModifiers() => $_has(0);
+  void clearFunctionModifiers() => clearField(1);
+
+  List<String> get childrenIds => $_getList(1);
+
+  String get returnType => $_getS(2, '');
+  set returnType(String v) {
+    $_setString(2, v);
+  }
+
+  bool hasReturnType() => $_has(2);
+  void clearReturnType() => clearField(3);
+
+  String get inferredReturnType => $_getS(3, '');
+  set inferredReturnType(String v) {
+    $_setString(3, v);
+  }
+
+  bool hasInferredReturnType() => $_has(3);
+  void clearInferredReturnType() => clearField(4);
+
+  List<ParameterInfoPB> get parameters => $_getList(4);
+
+  String get sideEffects => $_getS(5, '');
+  set sideEffects(String v) {
+    $_setString(5, v);
+  }
+
+  bool hasSideEffects() => $_has(5);
+  void clearSideEffects() => clearField(6);
+
+  int get inlinedCount => $_get(6, 0);
+  set inlinedCount(int v) {
+    $_setSignedInt32(6, v);
+  }
+
+  bool hasInlinedCount() => $_has(6);
+  void clearInlinedCount() => clearField(7);
+
+  String get code => $_getS(7, '');
+  set code(String v) {
+    $_setString(7, v);
+  }
+
+  bool hasCode() => $_has(7);
+  void clearCode() => clearField(8);
+
+  MeasurementsPB get measurements => $_getN(8);
+  set measurements(MeasurementsPB v) {
+    setField(9, v);
+  }
+
+  bool hasMeasurements() => $_has(8);
+  void clearMeasurements() => clearField(9);
+}
+
+class _ReadonlyFunctionInfoPB extends FunctionInfoPB with ReadonlyMessageMixin {
+}
+
+class ClosureInfoPB extends GeneratedMessage {
+  static final BuilderInfo _i = new BuilderInfo('ClosureInfoPB')
+    ..aOS(1, 'functionId')
+    ..hasRequiredFields = false;
+
+  ClosureInfoPB() : super();
+  ClosureInfoPB.fromBuffer(List<int> i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromBuffer(i, r);
+  ClosureInfoPB.fromJson(String i,
+      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
+      : super.fromJson(i, r);
+  ClosureInfoPB clone() => new ClosureInfoPB()..mergeFromMessage(this);
+  BuilderInfo get info_ => _i;
+  static ClosureInfoPB create() => new ClosureInfoPB();
+  static PbList<ClosureInfoPB> createRepeated() => new PbList<ClosureInfoPB>();
+  static ClosureInfoPB getDefault() {
+    if (_defaultInstance == null)
+      _defaultInstance = new _ReadonlyClosureInfoPB();
+    return _defaultInstance;
+  }
+
+  static ClosureInfoPB _defaultInstance;
+  static void $checkItem(ClosureInfoPB v) {
+    if (v is! ClosureInfoPB) checkItemFailed(v, 'ClosureInfoPB');
+  }
+
+  String get functionId => $_getS(0, '');
+  set functionId(String v) {
+    $_setString(0, v);
+  }
+
+  bool hasFunctionId() => $_has(0);
+  void clearFunctionId() => clearField(1);
+}
+
+class _ReadonlyClosureInfoPB extends ClosureInfoPB with ReadonlyMessageMixin {}
diff --git a/lib/src/proto/info.pbenum.dart b/lib/src/proto/info.pbenum.dart
new file mode 100644
index 0000000..ee8ccb3
--- /dev/null
+++ b/lib/src/proto/info.pbenum.dart
@@ -0,0 +1,4 @@
+///
+//  Generated code. Do not modify.
+///
+// ignore_for_file: non_constant_identifier_names,library_prefixes
diff --git a/lib/src/proto/info.pbjson.dart b/lib/src/proto/info.pbjson.dart
new file mode 100644
index 0000000..c7e5e38
--- /dev/null
+++ b/lib/src/proto/info.pbjson.dart
@@ -0,0 +1,390 @@
+///
+//  Generated code. Do not modify.
+///
+// ignore_for_file: non_constant_identifier_names,library_prefixes
+
+const DependencyInfoPB$json = const {
+  '1': 'DependencyInfoPB',
+  '2': const [
+    const {'1': 'target_id', '3': 1, '4': 1, '5': 9, '10': 'targetId'},
+    const {'1': 'mask', '3': 2, '4': 1, '5': 9, '10': 'mask'},
+  ],
+};
+
+const AllInfoPB$json = const {
+  '1': 'AllInfoPB',
+  '2': const [
+    const {
+      '1': 'program',
+      '3': 1,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.ProgramInfoPB',
+      '10': 'program'
+    },
+    const {
+      '1': 'all_infos',
+      '3': 2,
+      '4': 3,
+      '5': 11,
+      '6': '.dart2js_info.proto.AllInfoPB.AllInfosEntry',
+      '10': 'allInfos'
+    },
+  ],
+  '3': const [AllInfoPB_AllInfosEntry$json],
+};
+
+const AllInfoPB_AllInfosEntry$json = const {
+  '1': 'AllInfosEntry',
+  '2': const [
+    const {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},
+    const {
+      '1': 'value',
+      '3': 2,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.InfoPB',
+      '10': 'value'
+    },
+  ],
+  '7': const {'7': true},
+};
+
+const InfoPB$json = const {
+  '1': 'InfoPB',
+  '2': const [
+    const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
+    const {'1': 'id', '3': 2, '4': 1, '5': 5, '10': 'id'},
+    const {'1': 'serialized_id', '3': 3, '4': 1, '5': 9, '10': 'serializedId'},
+    const {'1': 'coverage_id', '3': 4, '4': 1, '5': 9, '10': 'coverageId'},
+    const {'1': 'size', '3': 5, '4': 1, '5': 5, '10': 'size'},
+    const {'1': 'parent_id', '3': 6, '4': 1, '5': 9, '10': 'parentId'},
+    const {
+      '1': 'uses',
+      '3': 7,
+      '4': 3,
+      '5': 11,
+      '6': '.dart2js_info.proto.DependencyInfoPB',
+      '10': 'uses'
+    },
+    const {
+      '1': 'library_info',
+      '3': 100,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.LibraryInfoPB',
+      '9': 0,
+      '10': 'libraryInfo'
+    },
+    const {
+      '1': 'class_info',
+      '3': 101,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.ClassInfoPB',
+      '9': 0,
+      '10': 'classInfo'
+    },
+    const {
+      '1': 'function_info',
+      '3': 102,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.FunctionInfoPB',
+      '9': 0,
+      '10': 'functionInfo'
+    },
+    const {
+      '1': 'field_info',
+      '3': 103,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.FieldInfoPB',
+      '9': 0,
+      '10': 'fieldInfo'
+    },
+    const {
+      '1': 'constant_info',
+      '3': 104,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.ConstantInfoPB',
+      '9': 0,
+      '10': 'constantInfo'
+    },
+    const {
+      '1': 'output_unit_info',
+      '3': 105,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.OutputUnitInfoPB',
+      '9': 0,
+      '10': 'outputUnitInfo'
+    },
+    const {
+      '1': 'typedef_info',
+      '3': 106,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.TypedefInfoPB',
+      '9': 0,
+      '10': 'typedefInfo'
+    },
+    const {
+      '1': 'closure_info',
+      '3': 107,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.ClosureInfoPB',
+      '9': 0,
+      '10': 'closureInfo'
+    },
+  ],
+  '8': const [
+    const {'1': 'concrete'},
+  ],
+  '9': const [
+    const {'1': 8, '2': 100},
+  ],
+};
+
+const ProgramInfoPB$json = const {
+  '1': 'ProgramInfoPB',
+  '2': const [
+    const {'1': 'entrypoint_id', '3': 1, '4': 1, '5': 9, '10': 'entrypointId'},
+    const {'1': 'size', '3': 2, '4': 1, '5': 5, '10': 'size'},
+    const {
+      '1': 'dart2js_version',
+      '3': 3,
+      '4': 1,
+      '5': 9,
+      '10': 'dart2jsVersion'
+    },
+    const {
+      '1': 'compilation_moment',
+      '3': 4,
+      '4': 1,
+      '5': 3,
+      '10': 'compilationMoment'
+    },
+    const {
+      '1': 'compilation_duration',
+      '3': 5,
+      '4': 1,
+      '5': 3,
+      '10': 'compilationDuration'
+    },
+    const {
+      '1': 'to_proto_duration',
+      '3': 6,
+      '4': 1,
+      '5': 3,
+      '10': 'toProtoDuration'
+    },
+    const {
+      '1': 'dump_info_duration',
+      '3': 7,
+      '4': 1,
+      '5': 3,
+      '10': 'dumpInfoDuration'
+    },
+    const {
+      '1': 'no_such_method_enabled',
+      '3': 8,
+      '4': 1,
+      '5': 8,
+      '10': 'noSuchMethodEnabled'
+    },
+    const {
+      '1': 'is_runtime_type_used',
+      '3': 9,
+      '4': 1,
+      '5': 8,
+      '10': 'isRuntimeTypeUsed'
+    },
+    const {
+      '1': 'is_isolate_used',
+      '3': 10,
+      '4': 1,
+      '5': 8,
+      '10': 'isIsolateUsed'
+    },
+    const {
+      '1': 'is_function_apply_used',
+      '3': 11,
+      '4': 1,
+      '5': 8,
+      '10': 'isFunctionApplyUsed'
+    },
+    const {
+      '1': 'is_mirrors_used',
+      '3': 12,
+      '4': 1,
+      '5': 8,
+      '10': 'isMirrorsUsed'
+    },
+    const {'1': 'minified', '3': 13, '4': 1, '5': 8, '10': 'minified'},
+  ],
+};
+
+const LibraryInfoPB$json = const {
+  '1': 'LibraryInfoPB',
+  '2': const [
+    const {'1': 'uri', '3': 1, '4': 1, '5': 9, '10': 'uri'},
+    const {'1': 'children_ids', '3': 2, '4': 3, '5': 9, '10': 'childrenIds'},
+  ],
+};
+
+const OutputUnitInfoPB$json = const {
+  '1': 'OutputUnitInfoPB',
+  '2': const [
+    const {'1': 'imports', '3': 1, '4': 3, '5': 9, '10': 'imports'},
+  ],
+};
+
+const ClassInfoPB$json = const {
+  '1': 'ClassInfoPB',
+  '2': const [
+    const {'1': 'is_abstract', '3': 1, '4': 1, '5': 8, '10': 'isAbstract'},
+    const {'1': 'children_ids', '3': 2, '4': 3, '5': 9, '10': 'childrenIds'},
+  ],
+};
+
+const ConstantInfoPB$json = const {
+  '1': 'ConstantInfoPB',
+  '2': const [
+    const {'1': 'code', '3': 1, '4': 1, '5': 9, '10': 'code'},
+  ],
+};
+
+const FieldInfoPB$json = const {
+  '1': 'FieldInfoPB',
+  '2': const [
+    const {'1': 'type', '3': 1, '4': 1, '5': 9, '10': 'type'},
+    const {'1': 'inferred_type', '3': 2, '4': 1, '5': 9, '10': 'inferredType'},
+    const {'1': 'children_ids', '3': 3, '4': 3, '5': 9, '10': 'childrenIds'},
+    const {'1': 'code', '3': 4, '4': 1, '5': 9, '10': 'code'},
+    const {'1': 'is_const', '3': 5, '4': 1, '5': 8, '10': 'isConst'},
+    const {
+      '1': 'initializer_id',
+      '3': 6,
+      '4': 1,
+      '5': 9,
+      '10': 'initializerId'
+    },
+  ],
+};
+
+const TypedefInfoPB$json = const {
+  '1': 'TypedefInfoPB',
+  '2': const [
+    const {'1': 'type', '3': 1, '4': 1, '5': 9, '10': 'type'},
+  ],
+};
+
+const FunctionModifiersPB$json = const {
+  '1': 'FunctionModifiersPB',
+  '2': const [
+    const {'1': 'is_static', '3': 1, '4': 1, '5': 8, '10': 'isStatic'},
+    const {'1': 'is_const', '3': 2, '4': 1, '5': 8, '10': 'isConst'},
+    const {'1': 'is_factory', '3': 3, '4': 1, '5': 8, '10': 'isFactory'},
+    const {'1': 'is_external', '3': 4, '4': 1, '5': 8, '10': 'isExternal'},
+  ],
+};
+
+const ParameterInfoPB$json = const {
+  '1': 'ParameterInfoPB',
+  '2': const [
+    const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
+    const {'1': 'type', '3': 2, '4': 1, '5': 9, '10': 'type'},
+    const {'1': 'declared_type', '3': 3, '4': 1, '5': 9, '10': 'declaredType'},
+  ],
+};
+
+const MeasurementEntryPB$json = const {
+  '1': 'MeasurementEntryPB',
+  '2': const [
+    const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
+    const {'1': 'values', '3': 2, '4': 3, '5': 5, '10': 'values'},
+  ],
+};
+
+const MeasurementCounterPB$json = const {
+  '1': 'MeasurementCounterPB',
+  '2': const [
+    const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
+    const {'1': 'value', '3': 2, '4': 1, '5': 5, '10': 'value'},
+  ],
+};
+
+const MeasurementsPB$json = const {
+  '1': 'MeasurementsPB',
+  '2': const [
+    const {'1': 'source_file', '3': 1, '4': 1, '5': 9, '10': 'sourceFile'},
+    const {
+      '1': 'entries',
+      '3': 2,
+      '4': 3,
+      '5': 11,
+      '6': '.dart2js_info.proto.MeasurementEntryPB',
+      '10': 'entries'
+    },
+    const {
+      '1': 'counters',
+      '3': 3,
+      '4': 3,
+      '5': 11,
+      '6': '.dart2js_info.proto.MeasurementCounterPB',
+      '10': 'counters'
+    },
+  ],
+};
+
+const FunctionInfoPB$json = const {
+  '1': 'FunctionInfoPB',
+  '2': const [
+    const {
+      '1': 'function_modifiers',
+      '3': 1,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.FunctionModifiersPB',
+      '10': 'functionModifiers'
+    },
+    const {'1': 'children_ids', '3': 2, '4': 3, '5': 9, '10': 'childrenIds'},
+    const {'1': 'return_type', '3': 3, '4': 1, '5': 9, '10': 'returnType'},
+    const {
+      '1': 'inferred_return_type',
+      '3': 4,
+      '4': 1,
+      '5': 9,
+      '10': 'inferredReturnType'
+    },
+    const {
+      '1': 'parameters',
+      '3': 5,
+      '4': 3,
+      '5': 11,
+      '6': '.dart2js_info.proto.ParameterInfoPB',
+      '10': 'parameters'
+    },
+    const {'1': 'side_effects', '3': 6, '4': 1, '5': 9, '10': 'sideEffects'},
+    const {'1': 'inlined_count', '3': 7, '4': 1, '5': 5, '10': 'inlinedCount'},
+    const {'1': 'code', '3': 8, '4': 1, '5': 9, '10': 'code'},
+    const {
+      '1': 'measurements',
+      '3': 9,
+      '4': 1,
+      '5': 11,
+      '6': '.dart2js_info.proto.MeasurementsPB',
+      '10': 'measurements'
+    },
+  ],
+};
+
+const ClosureInfoPB$json = const {
+  '1': 'ClosureInfoPB',
+  '2': const [
+    const {'1': 'function_id', '3': 1, '4': 1, '5': 9, '10': 'functionId'},
+  ],
+};
diff --git a/lib/src/proto/info.pbserver.dart b/lib/src/proto/info.pbserver.dart
new file mode 100644
index 0000000..861ed82
--- /dev/null
+++ b/lib/src/proto/info.pbserver.dart
@@ -0,0 +1,6 @@
+///
+//  Generated code. Do not modify.
+///
+// ignore_for_file: non_constant_identifier_names,library_prefixes
+
+export 'info.pb.dart';
diff --git a/pubspec.yaml b/pubspec.yaml
index aab8c3e..92f012c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -12,7 +12,9 @@
   args: '>=0.13.0 <2.0.0'
   charcode: ^1.1.0
   collection: ^1.10.1
+  fixnum: ^0.10.5
   path: ^1.3.6
+  protobuf: '>=0.9.0'
   quiver: '>=0.21.0 <0.26.0'
   shelf: '>=0.6.1+2 <0.8.0'
   shelf_static: ^0.2.4
@@ -27,6 +29,7 @@
   dart2js_info_deferred_library_check:  deferred_library_check
   dart2js_info_deferred_library_size:   deferred_library_size
   dart2js_info_deferred_library_layout: deferred_library_layout
+  dart2js_info_json_to_proto:           info_json_to_proto
   dart2js_info_function_size_analysis:  function_size_analysis
   dart2js_info_library_size_split:      library_size_split
   dart2js_info_live_code_size_analysis: live_code_size_analysis
diff --git a/test/json_to_proto_test.dart b/test/json_to_proto_test.dart
new file mode 100644
index 0000000..d318bfa
--- /dev/null
+++ b/test/json_to_proto_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:dart2js_info/info.dart';
+import 'package:dart2js_info/proto_info_codec.dart';
+import 'package:test/test.dart';
+
+main() {
+  group('json to proto conversion', () {
+    test('hello_world', () {
+      final helloWorld = new File('test/hello_world/hello_world.js.info.json');
+      final json = jsonDecode(helloWorld.readAsStringSync());
+      final decoded = new AllInfoJsonCodec().decode(json);
+      final proto = new AllInfoProtoCodec().encode(decoded);
+
+      expect(proto.program.entrypointId, isNotNull);
+      expect(proto.program.size, 10324);
+      expect(proto.program.compilationMoment.toInt(),
+          DateTime.parse("2017-04-17 09:46:41.661617").microsecondsSinceEpoch);
+      expect(proto.program.toProtoDuration.toInt(),
+          new Duration(milliseconds: 4).inMicroseconds);
+      expect(proto.program.dumpInfoDuration.toInt(),
+          new Duration(milliseconds: 0).inMicroseconds);
+      expect(proto.program.noSuchMethodEnabled, isFalse);
+      expect(proto.program.minified, isFalse);
+    });
+  });
+}