|
@@ -134,12 +134,37 @@ bool IsReserved(const string& ident) {
|
|
|
|
|
|
// Returns a copy of |filename| with any trailing ".protodevel" or ".proto
|
|
// Returns a copy of |filename| with any trailing ".protodevel" or ".proto
|
|
// suffix stripped.
|
|
// suffix stripped.
|
|
|
|
+// TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc.
|
|
string StripProto(const string& filename) {
|
|
string StripProto(const string& filename) {
|
|
const char* suffix = HasSuffixString(filename, ".protodevel")
|
|
const char* suffix = HasSuffixString(filename, ".protodevel")
|
|
? ".protodevel" : ".proto";
|
|
? ".protodevel" : ".proto";
|
|
return StripSuffixString(filename, suffix);
|
|
return StripSuffixString(filename, suffix);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript
|
|
|
|
+// file foo/bar/baz.js.
|
|
|
|
+string GetJSFilename(const string& filename) {
|
|
|
|
+ const char* suffix = HasSuffixString(filename, ".protodevel")
|
|
|
|
+ ? ".protodevel" : ".proto";
|
|
|
|
+ return StripSuffixString(filename, suffix) + "_pb.js";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Returns the alias we assign to the module of the given .proto filename
|
|
|
|
+// when importing.
|
|
|
|
+string ModuleAlias(const string& filename) {
|
|
|
|
+ // This scheme could technically cause problems if a file includes any 2 of:
|
|
|
|
+ // foo/bar_baz.proto
|
|
|
|
+ // foo_bar_baz.proto
|
|
|
|
+ // foo_bar/baz.proto
|
|
|
|
+ //
|
|
|
|
+ // We'll worry about this problem if/when we actually see it. This name isn't
|
|
|
|
+ // exposed to users so we can change it later if we need to.
|
|
|
|
+ string basename = StripProto(filename);
|
|
|
|
+ StripString(&basename, "-", '$');
|
|
|
|
+ StripString(&basename, "/", '_');
|
|
|
|
+ return basename + "_pb";
|
|
|
|
+}
|
|
|
|
+
|
|
// Returns the fully normalized JavaScript path for the given
|
|
// Returns the fully normalized JavaScript path for the given
|
|
// file descriptor's package.
|
|
// file descriptor's package.
|
|
string GetPath(const GeneratorOptions& options,
|
|
string GetPath(const GeneratorOptions& options,
|
|
@@ -215,6 +240,26 @@ string GetPath(const GeneratorOptions& options,
|
|
value_descriptor->type()) + "." + value_descriptor->name();
|
|
value_descriptor->type()) + "." + value_descriptor->name();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+string MaybeCrossFileRef(const GeneratorOptions& options,
|
|
|
|
+ const FileDescriptor* from_file,
|
|
|
|
+ const Descriptor* to_message) {
|
|
|
|
+ if (options.import_style == GeneratorOptions::IMPORT_COMMONJS &&
|
|
|
|
+ from_file != to_message->file()) {
|
|
|
|
+ // Cross-file ref in CommonJS needs to use the module alias instead of
|
|
|
|
+ // the global name.
|
|
|
|
+ return ModuleAlias(to_message->file()->name()) + "." + to_message->name();
|
|
|
|
+ } else {
|
|
|
|
+ // Within a single file we use a full name.
|
|
|
|
+ return GetPath(options, to_message);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+string SubmessageTypeRef(const GeneratorOptions& options,
|
|
|
|
+ const FieldDescriptor* field) {
|
|
|
|
+ GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
|
|
|
|
+ return MaybeCrossFileRef(options, field->file(), field->message_type());
|
|
|
|
+}
|
|
|
|
+
|
|
// - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields
|
|
// - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields
|
|
// (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate,
|
|
// (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate,
|
|
// and with reserved words triggering a "pb_" prefix.
|
|
// and with reserved words triggering a "pb_" prefix.
|
|
@@ -952,11 +997,13 @@ string RelativeTypeName(const FieldDescriptor* field) {
|
|
}
|
|
}
|
|
|
|
|
|
string JSExtensionsObjectName(const GeneratorOptions& options,
|
|
string JSExtensionsObjectName(const GeneratorOptions& options,
|
|
|
|
+ const FileDescriptor* from_file,
|
|
const Descriptor* desc) {
|
|
const Descriptor* desc) {
|
|
if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
|
|
if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
|
|
|
|
+ // TODO(haberman): fix this for the IMPORT_COMMONJS case.
|
|
return "jspb.Message.messageSetExtensions";
|
|
return "jspb.Message.messageSetExtensions";
|
|
} else {
|
|
} else {
|
|
- return GetPath(options, desc) + ".extensions";
|
|
|
|
|
|
+ return MaybeCrossFileRef(options, from_file, desc) + ".extensions";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1113,19 +1160,24 @@ void Generator::GenerateHeader(const GeneratorOptions& options,
|
|
"\n");
|
|
"\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void Generator::FindProvidesForFile(const GeneratorOptions& options,
|
|
|
|
+ io::Printer* printer,
|
|
|
|
+ const FileDescriptor* file,
|
|
|
|
+ std::set<string>* provided) const {
|
|
|
|
+ for (int i = 0; i < file->message_type_count(); i++) {
|
|
|
|
+ FindProvidesForMessage(options, printer, file->message_type(i), provided);
|
|
|
|
+ }
|
|
|
|
+ for (int i = 0; i < file->enum_type_count(); i++) {
|
|
|
|
+ FindProvidesForEnum(options, printer, file->enum_type(i), provided);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
void Generator::FindProvides(const GeneratorOptions& options,
|
|
void Generator::FindProvides(const GeneratorOptions& options,
|
|
io::Printer* printer,
|
|
io::Printer* printer,
|
|
const vector<const FileDescriptor*>& files,
|
|
const vector<const FileDescriptor*>& files,
|
|
std::set<string>* provided) const {
|
|
std::set<string>* provided) const {
|
|
for (int i = 0; i < files.size(); i++) {
|
|
for (int i = 0; i < files.size(); i++) {
|
|
- for (int j = 0; j < files[i]->message_type_count(); j++) {
|
|
|
|
- FindProvidesForMessage(options, printer, files[i]->message_type(j),
|
|
|
|
- provided);
|
|
|
|
- }
|
|
|
|
- for (int j = 0; j < files[i]->enum_type_count(); j++) {
|
|
|
|
- FindProvidesForEnum(options, printer, files[i]->enum_type(j),
|
|
|
|
- provided);
|
|
|
|
- }
|
|
|
|
|
|
+ FindProvidesForFile(options, printer, files[i], provided);
|
|
}
|
|
}
|
|
|
|
|
|
printer->Print("\n");
|
|
printer->Print("\n");
|
|
@@ -1204,38 +1256,45 @@ void Generator::GenerateRequires(const GeneratorOptions& options,
|
|
io::Printer* printer,
|
|
io::Printer* printer,
|
|
const vector<const FileDescriptor*>& files,
|
|
const vector<const FileDescriptor*>& files,
|
|
std::set<string>* provided) const {
|
|
std::set<string>* provided) const {
|
|
- std::set<string> required;
|
|
|
|
- std::set<string> forwards;
|
|
|
|
- bool have_extensions = false;
|
|
|
|
- bool have_message = false;
|
|
|
|
-
|
|
|
|
- for (int i = 0; i < files.size(); i++) {
|
|
|
|
- for (int j = 0; j < files[i]->message_type_count(); j++) {
|
|
|
|
- FindRequiresForMessage(options,
|
|
|
|
- files[i]->message_type(j),
|
|
|
|
- &required, &forwards, &have_message);
|
|
|
|
- }
|
|
|
|
- if (!have_extensions && HasExtensions(files[i])) {
|
|
|
|
- have_extensions = true;
|
|
|
|
- }
|
|
|
|
|
|
+ if (options.import_style == GeneratorOptions::IMPORT_BROWSER) {
|
|
|
|
+ return;
|
|
|
|
+ } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
|
|
|
|
+ // For Closure imports we need to import every message type individually.
|
|
|
|
+ std::set<string> required;
|
|
|
|
+ std::set<string> forwards;
|
|
|
|
+ bool have_extensions = false;
|
|
|
|
+ bool have_message = false;
|
|
|
|
|
|
- for (int j = 0; j < files[i]->extension_count(); j++) {
|
|
|
|
- const FieldDescriptor* extension = files[i]->extension(j);
|
|
|
|
- if (IgnoreField(extension)) {
|
|
|
|
- continue;
|
|
|
|
|
|
+ for (int i = 0; i < files.size(); i++) {
|
|
|
|
+ for (int j = 0; j < files[i]->message_type_count(); j++) {
|
|
|
|
+ FindRequiresForMessage(options,
|
|
|
|
+ files[i]->message_type(j),
|
|
|
|
+ &required, &forwards, &have_message);
|
|
}
|
|
}
|
|
- if (extension->containing_type()->full_name() !=
|
|
|
|
- "google.protobuf.bridge.MessageSet") {
|
|
|
|
- required.insert(GetPath(options, extension->containing_type()));
|
|
|
|
|
|
+ if (!have_extensions && HasExtensions(files[i])) {
|
|
|
|
+ have_extensions = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (int j = 0; j < files[i]->extension_count(); j++) {
|
|
|
|
+ const FieldDescriptor* extension = files[i]->extension(j);
|
|
|
|
+ if (IgnoreField(extension)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (extension->containing_type()->full_name() !=
|
|
|
|
+ "google.protobuf.bridge.MessageSet") {
|
|
|
|
+ required.insert(GetPath(options, extension->containing_type()));
|
|
|
|
+ }
|
|
|
|
+ FindRequiresForField(options, extension, &required, &forwards);
|
|
|
|
+ have_extensions = true;
|
|
}
|
|
}
|
|
- FindRequiresForField(options, extension, &required, &forwards);
|
|
|
|
- have_extensions = true;
|
|
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- GenerateRequiresImpl(options, printer, &required, &forwards, provided,
|
|
|
|
- /* require_jspb = */ have_message,
|
|
|
|
- /* require_extension = */ have_extensions);
|
|
|
|
|
|
+ GenerateRequiresImpl(options, printer, &required, &forwards, provided,
|
|
|
|
+ /* require_jspb = */ have_message,
|
|
|
|
+ /* require_extension = */ have_extensions);
|
|
|
|
+ } else if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
|
|
|
|
+ // CommonJS imports are based on files
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
void Generator::GenerateRequires(const GeneratorOptions& options,
|
|
void Generator::GenerateRequires(const GeneratorOptions& options,
|
|
@@ -1406,6 +1465,19 @@ void Generator::GenerateClass(const GeneratorOptions& options,
|
|
if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
|
|
if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
|
|
GenerateClassExtensionFieldInfo(options, printer, desc);
|
|
GenerateClassExtensionFieldInfo(options, printer, desc);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
|
|
|
|
+ printer->Print(
|
|
|
|
+ "exports.$name$ = $fullName$;\n",
|
|
|
|
+ "name", desc->name(),
|
|
|
|
+ "fullName", GetPath(options, desc));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) {
|
|
|
|
+ for (int i = 0; i < desc->extension_count(); i++) {
|
|
|
|
+ GenerateExtension(options, printer, desc->extension(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// Recurse on nested types.
|
|
// Recurse on nested types.
|
|
@@ -1623,7 +1695,7 @@ void Generator::GenerateClassToObject(const GeneratorOptions& options,
|
|
"obj,\n"
|
|
"obj,\n"
|
|
" $extObject$, $class$.prototype.getExtension,\n"
|
|
" $extObject$, $class$.prototype.getExtension,\n"
|
|
" includeInstance);\n",
|
|
" includeInstance);\n",
|
|
- "extObject", JSExtensionsObjectName(options, desc),
|
|
|
|
|
|
+ "extObject", JSExtensionsObjectName(options, desc->file(), desc),
|
|
"class", GetPath(options, desc));
|
|
"class", GetPath(options, desc));
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1652,13 +1724,13 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
|
|
printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
|
|
printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
|
|
" $type$.toObject, includeInstance)",
|
|
" $type$.toObject, includeInstance)",
|
|
"getter", JSGetterName(field),
|
|
"getter", JSGetterName(field),
|
|
- "type", GetPath(options, field->message_type()));
|
|
|
|
|
|
+ "type", SubmessageTypeRef(options, field));
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
printer->Print("(f = msg.get$getter$()) && "
|
|
printer->Print("(f = msg.get$getter$()) && "
|
|
"$type$.toObject(includeInstance, f)",
|
|
"$type$.toObject(includeInstance, f)",
|
|
"getter", JSGetterName(field),
|
|
"getter", JSGetterName(field),
|
|
- "type", GetPath(options, field->message_type()));
|
|
|
|
|
|
+ "type", SubmessageTypeRef(options, field));
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
// Simple field (singular or repeated).
|
|
// Simple field (singular or repeated).
|
|
@@ -1723,7 +1795,7 @@ void Generator::GenerateClassFieldFromObject(
|
|
" }));\n",
|
|
" }));\n",
|
|
"name", JSObjectFieldName(field),
|
|
"name", JSObjectFieldName(field),
|
|
"index", JSFieldIndex(field),
|
|
"index", JSFieldIndex(field),
|
|
- "fieldclass", GetPath(options, field->message_type()));
|
|
|
|
|
|
+ "fieldclass", SubmessageTypeRef(options, field));
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
printer->Print(
|
|
printer->Print(
|
|
@@ -1731,7 +1803,7 @@ void Generator::GenerateClassFieldFromObject(
|
|
" msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
|
|
" msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
|
|
"name", JSObjectFieldName(field),
|
|
"name", JSObjectFieldName(field),
|
|
"index", JSFieldIndex(field),
|
|
"index", JSFieldIndex(field),
|
|
- "fieldclass", GetPath(options, field->message_type()));
|
|
|
|
|
|
+ "fieldclass", SubmessageTypeRef(options, field));
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
// Simple (primitive) field.
|
|
// Simple (primitive) field.
|
|
@@ -1815,7 +1887,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
|
|
/* always_singular = */ false),
|
|
/* always_singular = */ false),
|
|
"rpt", (field->is_repeated() ? "Repeated" : ""),
|
|
"rpt", (field->is_repeated() ? "Repeated" : ""),
|
|
"index", JSFieldIndex(field),
|
|
"index", JSFieldIndex(field),
|
|
- "wrapperclass", GetPath(options, field->message_type()),
|
|
|
|
|
|
+ "wrapperclass", SubmessageTypeRef(options, field),
|
|
"required", (field->label() == FieldDescriptor::LABEL_REQUIRED ?
|
|
"required", (field->label() == FieldDescriptor::LABEL_REQUIRED ?
|
|
", 1" : ""));
|
|
", 1" : ""));
|
|
printer->Print(
|
|
printer->Print(
|
|
@@ -2043,7 +2115,7 @@ void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options,
|
|
" $class$.prototype.getExtension,\n"
|
|
" $class$.prototype.getExtension,\n"
|
|
" $class$.prototype.setExtension);\n"
|
|
" $class$.prototype.setExtension);\n"
|
|
" break;\n",
|
|
" break;\n",
|
|
- "extobj", JSExtensionsObjectName(options, desc),
|
|
|
|
|
|
+ "extobj", JSExtensionsObjectName(options, desc->file(), desc),
|
|
"class", GetPath(options, desc));
|
|
"class", GetPath(options, desc));
|
|
} else {
|
|
} else {
|
|
printer->Print(
|
|
printer->Print(
|
|
@@ -2073,7 +2145,7 @@ void Generator::GenerateClassDeserializeBinaryField(
|
|
" var value = new $fieldclass$;\n"
|
|
" var value = new $fieldclass$;\n"
|
|
" reader.read$msgOrGroup$($grpfield$value,"
|
|
" reader.read$msgOrGroup$($grpfield$value,"
|
|
"$fieldclass$.deserializeBinaryFromReader);\n",
|
|
"$fieldclass$.deserializeBinaryFromReader);\n",
|
|
- "fieldclass", GetPath(options, field->message_type()),
|
|
|
|
|
|
+ "fieldclass", SubmessageTypeRef(options, field),
|
|
"msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
|
|
"msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
|
|
"Group" : "Message",
|
|
"Group" : "Message",
|
|
"grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
|
|
"grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
|
|
@@ -2149,7 +2221,7 @@ void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options,
|
|
printer->Print(
|
|
printer->Print(
|
|
" jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n"
|
|
" jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n"
|
|
" $class$.prototype.getExtension);\n",
|
|
" $class$.prototype.getExtension);\n",
|
|
- "extobj", JSExtensionsObjectName(options, desc),
|
|
|
|
|
|
+ "extobj", JSExtensionsObjectName(options, desc->file(), desc),
|
|
"class", GetPath(options, desc));
|
|
"class", GetPath(options, desc));
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2222,7 +2294,7 @@ void Generator::GenerateClassSerializeBinaryField(
|
|
printer->Print(
|
|
printer->Print(
|
|
",\n"
|
|
",\n"
|
|
" $submsg$.serializeBinaryToWriter\n",
|
|
" $submsg$.serializeBinaryToWriter\n",
|
|
- "submsg", GetPath(options, field->message_type()));
|
|
|
|
|
|
+ "submsg", SubmessageTypeRef(options, field));
|
|
} else {
|
|
} else {
|
|
printer->Print("\n");
|
|
printer->Print("\n");
|
|
}
|
|
}
|
|
@@ -2290,9 +2362,9 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
|
|
"index", SimpleItoa(field->number()),
|
|
"index", SimpleItoa(field->number()),
|
|
"name", JSObjectFieldName(field),
|
|
"name", JSObjectFieldName(field),
|
|
"ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
|
|
"ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
|
|
- GetPath(options, field->message_type()) : string("null")),
|
|
|
|
|
|
+ SubmessageTypeRef(options, field) : string("null")),
|
|
"toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
|
|
"toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
|
|
- (GetPath(options, field->message_type()) + ".toObject") :
|
|
|
|
|
|
+ (SubmessageTypeRef(options, field) + ".toObject") :
|
|
string("null")),
|
|
string("null")),
|
|
"repeated", (field->is_repeated() ? "1" : "0"));
|
|
"repeated", (field->is_repeated() ? "1" : "0"));
|
|
|
|
|
|
@@ -2308,11 +2380,11 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
|
|
"binaryWriterFn", JSBinaryWriterMethodName(field),
|
|
"binaryWriterFn", JSBinaryWriterMethodName(field),
|
|
"binaryMessageSerializeFn",
|
|
"binaryMessageSerializeFn",
|
|
(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
|
|
(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
|
|
- (GetPath(options, field->message_type()) +
|
|
|
|
|
|
+ (SubmessageTypeRef(options, field) +
|
|
".serializeBinaryToWriter") : "null",
|
|
".serializeBinaryToWriter") : "null",
|
|
"binaryMessageDeserializeFn",
|
|
"binaryMessageDeserializeFn",
|
|
(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
|
|
(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
|
|
- (GetPath(options, field->message_type()) +
|
|
|
|
|
|
+ (SubmessageTypeRef(options, field) +
|
|
".deserializeBinaryFromReader") : "null",
|
|
".deserializeBinaryFromReader") : "null",
|
|
"isPacked", (field->is_packed() ? "true" : "false"));
|
|
"isPacked", (field->is_packed() ? "true" : "false"));
|
|
} else {
|
|
} else {
|
|
@@ -2324,7 +2396,8 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
|
|
"// toObject() will function correctly.\n"
|
|
"// toObject() will function correctly.\n"
|
|
"$extendName$[$index$] = $class$.$name$;\n"
|
|
"$extendName$[$index$] = $class$.$name$;\n"
|
|
"\n",
|
|
"\n",
|
|
- "extendName", JSExtensionsObjectName(options, field->containing_type()),
|
|
|
|
|
|
+ "extendName", JSExtensionsObjectName(options, field->file(),
|
|
|
|
+ field->containing_type()),
|
|
"index", SimpleItoa(field->number()),
|
|
"index", SimpleItoa(field->number()),
|
|
"class", extension_scope,
|
|
"class", extension_scope,
|
|
"name", JSObjectFieldName(field));
|
|
"name", JSObjectFieldName(field));
|
|
@@ -2364,6 +2437,19 @@ bool GeneratorOptions::ParseFromOptions(
|
|
namespace_prefix = options[i].second;
|
|
namespace_prefix = options[i].second;
|
|
} else if (options[i].first == "library") {
|
|
} else if (options[i].first == "library") {
|
|
library = options[i].second;
|
|
library = options[i].second;
|
|
|
|
+ } else if (options[i].first == "import_style") {
|
|
|
|
+ if (options[i].second == "closure") {
|
|
|
|
+ import_style = IMPORT_CLOSURE;
|
|
|
|
+ } else if (options[i].second == "commonjs") {
|
|
|
|
+ import_style = IMPORT_COMMONJS;
|
|
|
|
+ } else if (options[i].second == "browser") {
|
|
|
|
+ import_style = IMPORT_BROWSER;
|
|
|
|
+ } else if (options[i].second == "es6") {
|
|
|
|
+ import_style = IMPORT_ES6;
|
|
|
|
+ } else {
|
|
|
|
+ *error = "Unknown import style " + options[i].second + ", expected " +
|
|
|
|
+ "one of: closure, commonjs, browser, es6.";
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
// Assume any other option is an output directory, as long as it is a bare
|
|
// Assume any other option is an output directory, as long as it is a bare
|
|
// `key` rather than a `key=value` option.
|
|
// `key` rather than a `key=value` option.
|
|
@@ -2375,6 +2461,11 @@ bool GeneratorOptions::ParseFromOptions(
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!library.empty() && import_style != IMPORT_CLOSURE) {
|
|
|
|
+ *error = "The library option should only be used for "
|
|
|
|
+ "import_style=closure";
|
|
|
|
+ }
|
|
|
|
+
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2418,6 +2509,47 @@ void Generator::GenerateFileAndDeps(
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void Generator::GenerateFile(const GeneratorOptions& options,
|
|
|
|
+ io::Printer* printer,
|
|
|
|
+ const FileDescriptor* file) const {
|
|
|
|
+ GenerateHeader(options, printer);
|
|
|
|
+
|
|
|
|
+ // Generate "require" statements.
|
|
|
|
+ if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
|
|
|
|
+ for (int i = 0; i < file->dependency_count(); i++) {
|
|
|
|
+ const std::string& name = file->dependency(i)->name();
|
|
|
|
+ printer->Print(
|
|
|
|
+ "var $alias$ = require('$file$');\n",
|
|
|
|
+ "alias", ModuleAlias(name),
|
|
|
|
+ "file", GetJSFilename(name));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // We aren't using Closure's import system, but we use goog.exportSymbol()
|
|
|
|
+ // to construct the expected tree of objects, eg.
|
|
|
|
+ //
|
|
|
|
+ // goog.exportSymbol('foo.bar.Baz', null, this);
|
|
|
|
+ //
|
|
|
|
+ // // Later generated code expects foo.bar = {} to exist:
|
|
|
|
+ // foo.bar.Baz = function() { /* ... */ }
|
|
|
|
+ std::set<std::string> provided;
|
|
|
|
+ FindProvidesForFile(options, printer, file, &provided);
|
|
|
|
+ //FindProvidesForFields(options, printer, extensions, &provided);
|
|
|
|
+ for (std::set<string>::iterator it = provided.begin();
|
|
|
|
+ it != provided.end(); ++it) {
|
|
|
|
+ printer->Print("goog.exportSymbol('$name$', null, this);\n",
|
|
|
|
+ "name", *it);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ GenerateClassesAndEnums(options, printer, file);
|
|
|
|
+
|
|
|
|
+ // Extensions nested inside messages are emitted inside
|
|
|
|
+ // GenerateClassesAndEnums().
|
|
|
|
+ for (int i = 0; i < file->extension_count(); i++) {
|
|
|
|
+ GenerateExtension(options, printer, file->extension(i));
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
|
|
bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
|
|
const string& parameter,
|
|
const string& parameter,
|
|
GeneratorContext* context,
|
|
GeneratorContext* context,
|
|
@@ -2430,10 +2562,14 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
- // We're either generating a single library file with definitions for message
|
|
|
|
- // and enum types in *all* FileDescriptor inputs, or we're generating a single
|
|
|
|
- // file for each type.
|
|
|
|
- if (options.library != "") {
|
|
|
|
|
|
+ // There are three schemes for where output files go:
|
|
|
|
+ //
|
|
|
|
+ // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file
|
|
|
|
+ // - import_style = IMPORT_CLOSURE, library empty: one output file per type
|
|
|
|
+ // - import_style != IMPORT_CLOSURE: one output file per .proto file
|
|
|
|
+ if (options.import_style == GeneratorOptions::IMPORT_CLOSURE &&
|
|
|
|
+ options.library != "") {
|
|
|
|
+ // All output should go in a single file.
|
|
string filename = options.output_dir + "/" + options.library + ".js";
|
|
string filename = options.output_dir + "/" + options.library + ".js";
|
|
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
|
|
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
|
|
GOOGLE_CHECK(output.get());
|
|
GOOGLE_CHECK(output.get());
|
|
@@ -2469,7 +2605,7 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
|
|
if (printer.failed()) {
|
|
if (printer.failed()) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
|
|
+ } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
|
|
// Collect all types, and print each type to a separate file. Pull out
|
|
// Collect all types, and print each type to a separate file. Pull out
|
|
// free-floating extensions while we make this pass.
|
|
// free-floating extensions while we make this pass.
|
|
map< string, vector<const FieldDescriptor*> > extensions_by_namespace;
|
|
map< string, vector<const FieldDescriptor*> > extensions_by_namespace;
|
|
@@ -2611,6 +2747,24 @@ bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ } else {
|
|
|
|
+ // Generate one output file per input (.proto) file.
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < files.size(); i++) {
|
|
|
|
+ const google::protobuf::FileDescriptor* file = files[i];
|
|
|
|
+
|
|
|
|
+ string filename = options.output_dir + "/" + GetJSFilename(file->name());
|
|
|
|
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
|
|
|
|
+ context->Open(filename));
|
|
|
|
+ GOOGLE_CHECK(output.get());
|
|
|
|
+ io::Printer printer(output.get(), '$');
|
|
|
|
+
|
|
|
|
+ GenerateFile(options, &printer, file);
|
|
|
|
+
|
|
|
|
+ if (printer.failed()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
return true;
|
|
return true;
|