Fix generation of extending nested messages in JavaScript (#2439)

* Fix generation of extending nested messages in JavaScript

* Added missing test8.proto to build
diff --git a/Makefile.am b/Makefile.am
index 5ade9d2..db2f7a3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -853,6 +853,7 @@
   js/test3.proto                            \
   js/test4.proto                            \
   js/test5.proto                            \
+  js/test8.proto                            \
   js/test_bootstrap.js                      \
   js/testbinary.proto                       \
   js/testempty.proto
diff --git a/js/message_test.js b/js/message_test.js
index 082da94..6d7cdd2 100644
--- a/js/message_test.js
+++ b/js/message_test.js
@@ -39,6 +39,9 @@
 // CommonJS-LoadFromFile: google-protobuf jspb
 goog.require('jspb.Message');
 
+// CommonJS-LoadFromFile: test8_pb proto.jspb.exttest.nested
+goog.require('proto.jspb.exttest.nested.TestOuterMessage');
+
 // CommonJS-LoadFromFile: test5_pb proto.jspb.exttest.beta
 goog.require('proto.jspb.exttest.beta.floatingStrField');
 
@@ -588,6 +591,14 @@
     assertNotUndefined(proto.jspb.exttest.beta.floatingStrField);
   });
 
+  it('testNestedExtensions', function() {
+    var extendable = new proto.jspb.exttest.nested.TestNestedExtensionsMessage();
+    var extension = new proto.jspb.exttest.nested.TestOuterMessage.NestedExtensionMessage(['s1']);
+    extendable.setExtension(proto.jspb.exttest.nested.TestOuterMessage.innerExtension, extension);
+    assertObjectEquals(extension,
+        extendable.getExtension(proto.jspb.exttest.nested.TestOuterMessage.innerExtension));
+  });
+
   it('testToObject_extendedObject', function() {
     var extension1 = new proto.jspb.test.IsExtension(['ext1field']);
     var extension2 = new proto.jspb.test.Simple1(['str', ['s1', 's2'], true]);
diff --git a/js/test8.proto b/js/test8.proto
new file mode 100644
index 0000000..2ae80da
--- /dev/null
+++ b/js/test8.proto
@@ -0,0 +1,50 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
+package jspb.exttest.nested;
+
+message TestNestedExtensionsMessage {
+  optional int32 intfield = 1;
+  extensions 100 to max;
+}
+
+message TestOuterMessage {
+  message NestedExtensionMessage {
+    optional string ext1 = 1;
+  }
+  extend TestNestedExtensionsMessage {
+    optional NestedExtensionMessage inner_extension = 100;
+  }
+}
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index e6571f6..727ed09 100755
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -1865,7 +1865,19 @@
     // objects.
     GenerateClassDeserializeBinary(options, printer, desc);
     GenerateClassSerializeBinary(options, printer, desc);
+  }
 
+  // Recurse on nested types. These must come *before* the extension-field
+  // info generation in GenerateClassRegistration so that extensions that 
+  // reference nested types proceed the definitions of the nested types.
+  for (int i = 0; i < desc->enum_type_count(); i++) {
+    GenerateEnum(options, printer, desc->enum_type(i));
+  }
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    GenerateClass(options, printer, desc->nested_type(i));
+  }
+
+  if (!NamespaceOnly(desc)) {
     GenerateClassRegistration(options, printer, desc);
     GenerateClassFields(options, printer, desc);
     if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
@@ -1879,13 +1891,6 @@
     }
   }
 
-  // Recurse on nested types.
-  for (int i = 0; i < desc->enum_type_count(); i++) {
-    GenerateEnum(options, printer, desc->enum_type(i));
-  }
-  for (int i = 0; i < desc->nested_type_count(); i++) {
-    GenerateClass(options, printer, desc->nested_type(i));
-  }
 }
 
 void Generator::GenerateClassConstructor(const GeneratorOptions& options,