js_generator.cc 141 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. #include <assert.h>
  31. #include <google/protobuf/compiler/js/js_generator.h>
  32. #include <google/protobuf/compiler/js/well_known_types_embed.h>
  33. #include <google/protobuf/compiler/scc.h>
  34. #include <google/protobuf/descriptor.h>
  35. #include <google/protobuf/descriptor.pb.h>
  36. #include <google/protobuf/io/printer.h>
  37. #include <google/protobuf/io/zero_copy_stream.h>
  38. #include <google/protobuf/stubs/common.h>
  39. #include <google/protobuf/stubs/logging.h>
  40. #include <google/protobuf/stubs/stringprintf.h>
  41. #include <google/protobuf/stubs/strutil.h>
  42. #include <algorithm>
  43. #include <limits>
  44. #include <map>
  45. #include <memory>
  46. #include <string>
  47. #include <utility>
  48. #include <vector>
  49. namespace google {
  50. namespace protobuf {
  51. namespace compiler {
  52. namespace js {
  53. // Sorted list of JavaScript keywords. These cannot be used as names. If they
  54. // appear, we prefix them with "pb_".
  55. const char* kKeyword[] = {
  56. "abstract", "boolean", "break", "byte", "case",
  57. "catch", "char", "class", "const", "continue",
  58. "debugger", "default", "delete", "do", "double",
  59. "else", "enum", "export", "extends", "false",
  60. "final", "finally", "float", "for", "function",
  61. "goto", "if", "implements", "import", "in",
  62. "instanceof", "int", "interface", "long", "native",
  63. "new", "null", "package", "private", "protected",
  64. "public", "return", "short", "static", "super",
  65. "switch", "synchronized", "this", "throw", "throws",
  66. "transient", "try", "typeof", "var", "void",
  67. "volatile", "while", "with",
  68. };
  69. static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*);
  70. namespace {
  71. // The mode of operation for bytes fields. Historically JSPB always carried
  72. // bytes as JS {string}, containing base64 content by convention. With binary
  73. // and proto3 serialization the new convention is to represent it as binary
  74. // data in Uint8Array. See b/26173701 for background on the migration.
  75. enum BytesMode {
  76. BYTES_DEFAULT, // Default type for getBytesField to return.
  77. BYTES_B64, // Explicitly coerce to base64 string where needed.
  78. BYTES_U8, // Explicitly coerce to Uint8Array where needed.
  79. };
  80. bool IsReserved(const std::string& ident) {
  81. for (int i = 0; i < kNumKeyword; i++) {
  82. if (ident == kKeyword[i]) {
  83. return true;
  84. }
  85. }
  86. return false;
  87. }
  88. bool StrEndsWith(StringPiece sp, StringPiece x) {
  89. return sp.size() >= x.size() && sp.substr(sp.size() - x.size()) == x;
  90. }
  91. std::string GetSnakeFilename(const std::string& filename) {
  92. std::string snake_name = filename;
  93. ReplaceCharacters(&snake_name, "/", '_');
  94. return snake_name;
  95. }
  96. // Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript
  97. // file foo/bar/baz.js.
  98. std::string GetJSFilename(const GeneratorOptions& options,
  99. const std::string& filename) {
  100. return StripProto(filename) + options.GetFileNameExtension();
  101. }
  102. // Given a filename like foo/bar/baz.proto, returns the root directory
  103. // path ../../
  104. std::string GetRootPath(const std::string& from_filename,
  105. const std::string& to_filename) {
  106. if (to_filename.find("google/protobuf") == 0) {
  107. // Well-known types (.proto files in the google/protobuf directory) are
  108. // assumed to come from the 'google-protobuf' npm package. We may want to
  109. // generalize this exception later by letting others put generated code in
  110. // their own npm packages.
  111. return "google-protobuf/";
  112. }
  113. size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/');
  114. if (slashes == 0) {
  115. return "./";
  116. }
  117. std::string result = "";
  118. for (size_t i = 0; i < slashes; i++) {
  119. result += "../";
  120. }
  121. return result;
  122. }
  123. // Returns the alias we assign to the module of the given .proto filename
  124. // when importing.
  125. std::string ModuleAlias(const std::string& filename) {
  126. // This scheme could technically cause problems if a file includes any 2 of:
  127. // foo/bar_baz.proto
  128. // foo_bar_baz.proto
  129. // foo_bar/baz.proto
  130. //
  131. // We'll worry about this problem if/when we actually see it. This name isn't
  132. // exposed to users so we can change it later if we need to.
  133. std::string basename = StripProto(filename);
  134. ReplaceCharacters(&basename, "-", '$');
  135. ReplaceCharacters(&basename, "/", '_');
  136. ReplaceCharacters(&basename, ".", '_');
  137. return basename + "_pb";
  138. }
  139. // Returns the fully normalized JavaScript namespace for the given
  140. // file descriptor's package.
  141. std::string GetNamespace(const GeneratorOptions& options,
  142. const FileDescriptor* file) {
  143. if (!options.namespace_prefix.empty()) {
  144. return options.namespace_prefix;
  145. } else if (!file->package().empty()) {
  146. return "proto." + file->package();
  147. } else {
  148. return "proto";
  149. }
  150. }
  151. // Returns the name of the message with a leading dot and taking into account
  152. // nesting, for example ".OuterMessage.InnerMessage", or returns empty if
  153. // descriptor is null. This function does not handle namespacing, only message
  154. // nesting.
  155. std::string GetNestedMessageName(const Descriptor* descriptor) {
  156. if (descriptor == NULL) {
  157. return "";
  158. }
  159. std::string result =
  160. StripPrefixString(descriptor->full_name(), descriptor->file()->package());
  161. // Add a leading dot if one is not already present.
  162. if (!result.empty() && result[0] != '.') {
  163. result = "." + result;
  164. }
  165. return result;
  166. }
  167. // Returns the path prefix for a message or enumeration that
  168. // lives under the given file and containing type.
  169. std::string GetPrefix(const GeneratorOptions& options,
  170. const FileDescriptor* file_descriptor,
  171. const Descriptor* containing_type) {
  172. std::string prefix = GetNamespace(options, file_descriptor) +
  173. GetNestedMessageName(containing_type);
  174. if (!prefix.empty()) {
  175. prefix += ".";
  176. }
  177. return prefix;
  178. }
  179. // Returns the fully normalized JavaScript path prefix for the given
  180. // message descriptor.
  181. std::string GetMessagePathPrefix(const GeneratorOptions& options,
  182. const Descriptor* descriptor) {
  183. return GetPrefix(options, descriptor->file(), descriptor->containing_type());
  184. }
  185. // Returns the fully normalized JavaScript path for the given
  186. // message descriptor.
  187. std::string GetMessagePath(const GeneratorOptions& options,
  188. const Descriptor* descriptor) {
  189. return GetMessagePathPrefix(options, descriptor) + descriptor->name();
  190. }
  191. // Returns the fully normalized JavaScript path prefix for the given
  192. // enumeration descriptor.
  193. std::string GetEnumPathPrefix(const GeneratorOptions& options,
  194. const EnumDescriptor* enum_descriptor) {
  195. return GetPrefix(options, enum_descriptor->file(),
  196. enum_descriptor->containing_type());
  197. }
  198. // Returns the fully normalized JavaScript path for the given
  199. // enumeration descriptor.
  200. std::string GetEnumPath(const GeneratorOptions& options,
  201. const EnumDescriptor* enum_descriptor) {
  202. return GetEnumPathPrefix(options, enum_descriptor) + enum_descriptor->name();
  203. }
  204. std::string MaybeCrossFileRef(const GeneratorOptions& options,
  205. const FileDescriptor* from_file,
  206. const Descriptor* to_message) {
  207. if ((options.import_style == GeneratorOptions::kImportCommonJs ||
  208. options.import_style == GeneratorOptions::kImportCommonJsStrict) &&
  209. from_file != to_message->file()) {
  210. // Cross-file ref in CommonJS needs to use the module alias instead of
  211. // the global name.
  212. return ModuleAlias(to_message->file()->name()) +
  213. GetNestedMessageName(to_message->containing_type()) + "." +
  214. to_message->name();
  215. } else {
  216. // Within a single file we use a full name.
  217. return GetMessagePath(options, to_message);
  218. }
  219. }
  220. std::string SubmessageTypeRef(const GeneratorOptions& options,
  221. const FieldDescriptor* field) {
  222. GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
  223. return MaybeCrossFileRef(options, field->file(), field->message_type());
  224. }
  225. // - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields
  226. // (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate,
  227. // and with reserved words triggering a "pb_" prefix.
  228. // - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields
  229. // (use the name directly), then append "List" if appropriate, then append "$"
  230. // if resulting name is equal to a reserved word.
  231. // - Enums: just uppercase.
  232. // Locale-independent version of ToLower that deals only with ASCII A-Z.
  233. char ToLowerASCII(char c) {
  234. if (c >= 'A' && c <= 'Z') {
  235. return (c - 'A') + 'a';
  236. } else {
  237. return c;
  238. }
  239. }
  240. std::vector<std::string> ParseLowerUnderscore(const std::string& input) {
  241. std::vector<std::string> words;
  242. std::string running = "";
  243. for (int i = 0; i < input.size(); i++) {
  244. if (input[i] == '_') {
  245. if (!running.empty()) {
  246. words.push_back(running);
  247. running.clear();
  248. }
  249. } else {
  250. running += ToLowerASCII(input[i]);
  251. }
  252. }
  253. if (!running.empty()) {
  254. words.push_back(running);
  255. }
  256. return words;
  257. }
  258. std::vector<std::string> ParseUpperCamel(const std::string& input) {
  259. std::vector<std::string> words;
  260. std::string running = "";
  261. for (int i = 0; i < input.size(); i++) {
  262. if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) {
  263. words.push_back(running);
  264. running.clear();
  265. }
  266. running += ToLowerASCII(input[i]);
  267. }
  268. if (!running.empty()) {
  269. words.push_back(running);
  270. }
  271. return words;
  272. }
  273. std::string ToLowerCamel(const std::vector<std::string>& words) {
  274. std::string result;
  275. for (int i = 0; i < words.size(); i++) {
  276. std::string word = words[i];
  277. if (i == 0 && (word[0] >= 'A' && word[0] <= 'Z')) {
  278. word[0] = (word[0] - 'A') + 'a';
  279. } else if (i != 0 && (word[0] >= 'a' && word[0] <= 'z')) {
  280. word[0] = (word[0] - 'a') + 'A';
  281. }
  282. result += word;
  283. }
  284. return result;
  285. }
  286. std::string ToUpperCamel(const std::vector<std::string>& words) {
  287. std::string result;
  288. for (int i = 0; i < words.size(); i++) {
  289. std::string word = words[i];
  290. if (word[0] >= 'a' && word[0] <= 'z') {
  291. word[0] = (word[0] - 'a') + 'A';
  292. }
  293. result += word;
  294. }
  295. return result;
  296. }
  297. // Based on code from descriptor.cc (Thanks Kenton!)
  298. // Uppercases the entire string, turning ValueName into
  299. // VALUENAME.
  300. std::string ToEnumCase(const std::string& input) {
  301. std::string result;
  302. result.reserve(input.size());
  303. for (int i = 0; i < input.size(); i++) {
  304. if ('a' <= input[i] && input[i] <= 'z') {
  305. result.push_back(input[i] - 'a' + 'A');
  306. } else {
  307. result.push_back(input[i]);
  308. }
  309. }
  310. return result;
  311. }
  312. std::string ToLower(const std::string& input) {
  313. std::string result;
  314. result.reserve(input.size());
  315. for (int i = 0; i < input.size(); i++) {
  316. if ('A' <= input[i] && input[i] <= 'Z') {
  317. result.push_back(input[i] - 'A' + 'a');
  318. } else {
  319. result.push_back(input[i]);
  320. }
  321. }
  322. return result;
  323. }
  324. // When we're generating one output file per SCC, this is the filename
  325. // that top-level extensions should go in.
  326. // e.g. one proto file (test.proto):
  327. // package a;
  328. // extends Foo {
  329. // ...
  330. // }
  331. // If "with_filename" equals true, the extension filename will be
  332. // "proto.a_test_extensions.js", otherwise will be "proto.a.js"
  333. std::string GetExtensionFileName(const GeneratorOptions& options,
  334. const FileDescriptor* file,
  335. bool with_filename) {
  336. std::string snake_name = StripProto(GetSnakeFilename(file->name()));
  337. return options.output_dir + "/" + ToLower(GetNamespace(options, file)) +
  338. (with_filename ? ("_" + snake_name + "_extensions") : "") +
  339. options.GetFileNameExtension();
  340. }
  341. // When we're generating one output file per SCC, this is the filename
  342. // that all messages in the SCC should go in.
  343. // If with_package equals true, filename will have package prefix,
  344. // If the filename length is longer than 200, the filename will be the
  345. // SCC's proto filename with suffix "_long_sccs_(index)" (if with_package equals
  346. // true it still has package prefix)
  347. std::string GetMessagesFileName(const GeneratorOptions& options, const SCC* scc,
  348. bool with_package) {
  349. static std::map<const Descriptor*, std::string>* long_name_dict =
  350. new std::map<const Descriptor*, std::string>();
  351. std::string package_base =
  352. with_package
  353. ? ToLower(GetNamespace(options, scc->GetRepresentative()->file()) +
  354. "_")
  355. : "";
  356. std::string filename_base = "";
  357. std::vector<std::string> all_message_names;
  358. for (auto one_desc : scc->descriptors) {
  359. if (one_desc->containing_type() == nullptr) {
  360. all_message_names.push_back(ToLower(one_desc->name()));
  361. }
  362. }
  363. sort(all_message_names.begin(), all_message_names.end());
  364. for (auto one_message : all_message_names) {
  365. if (!filename_base.empty()) {
  366. filename_base += "_";
  367. }
  368. filename_base += one_message;
  369. }
  370. if (filename_base.size() + package_base.size() > 200) {
  371. if ((*long_name_dict).find(scc->GetRepresentative()) ==
  372. (*long_name_dict).end()) {
  373. std::string snake_name = StripProto(
  374. GetSnakeFilename(scc->GetRepresentative()->file()->name()));
  375. (*long_name_dict)[scc->GetRepresentative()] =
  376. StrCat(snake_name, "_long_sccs_",
  377. static_cast<uint64>((*long_name_dict).size()));
  378. }
  379. filename_base = (*long_name_dict)[scc->GetRepresentative()];
  380. }
  381. return options.output_dir + "/" + package_base + filename_base +
  382. options.GetFileNameExtension();
  383. }
  384. // When we're generating one output file per type name, this is the filename
  385. // that a top-level enum should go in.
  386. // If with_package equals true, filename will have package prefix.
  387. std::string GetEnumFileName(const GeneratorOptions& options,
  388. const EnumDescriptor* desc, bool with_package) {
  389. return options.output_dir + "/" +
  390. (with_package ? ToLower(GetNamespace(options, desc->file()) + "_")
  391. : "") +
  392. ToLower(desc->name()) + options.GetFileNameExtension();
  393. }
  394. // Returns the message/response ID, if set.
  395. std::string GetMessageId(const Descriptor* desc) { return std::string(); }
  396. bool IgnoreExtensionField(const FieldDescriptor* field) {
  397. // Exclude descriptor extensions from output "to avoid clutter" (from original
  398. // codegen).
  399. if (!field->is_extension()) return false;
  400. const FileDescriptor* file = field->containing_type()->file();
  401. return file->name() == "net/proto2/proto/descriptor.proto" ||
  402. file->name() == "google/protobuf/descriptor.proto";
  403. }
  404. // Used inside Google only -- do not remove.
  405. bool IsResponse(const Descriptor* desc) { return false; }
  406. bool IgnoreField(const FieldDescriptor* field) {
  407. return IgnoreExtensionField(field);
  408. }
  409. // Do we ignore this message type?
  410. bool IgnoreMessage(const Descriptor* d) { return d->options().map_entry(); }
  411. // Does JSPB ignore this entire oneof? True only if all fields are ignored.
  412. bool IgnoreOneof(const OneofDescriptor* oneof) {
  413. if (oneof->is_synthetic()) return true;
  414. for (int i = 0; i < oneof->field_count(); i++) {
  415. if (!IgnoreField(oneof->field(i))) {
  416. return false;
  417. }
  418. }
  419. return true;
  420. }
  421. std::string JSIdent(const GeneratorOptions& options,
  422. const FieldDescriptor* field, bool is_upper_camel,
  423. bool is_map, bool drop_list) {
  424. std::string result;
  425. if (field->type() == FieldDescriptor::TYPE_GROUP) {
  426. result = is_upper_camel
  427. ? ToUpperCamel(ParseUpperCamel(field->message_type()->name()))
  428. : ToLowerCamel(ParseUpperCamel(field->message_type()->name()));
  429. } else {
  430. result = is_upper_camel ? ToUpperCamel(ParseLowerUnderscore(field->name()))
  431. : ToLowerCamel(ParseLowerUnderscore(field->name()));
  432. }
  433. if (is_map || field->is_map()) {
  434. // JSPB-style or proto3-style map.
  435. result += "Map";
  436. } else if (!drop_list && field->is_repeated()) {
  437. // Repeated field.
  438. result += "List";
  439. }
  440. return result;
  441. }
  442. std::string JSObjectFieldName(const GeneratorOptions& options,
  443. const FieldDescriptor* field) {
  444. std::string name = JSIdent(options, field,
  445. /* is_upper_camel = */ false,
  446. /* is_map = */ false,
  447. /* drop_list = */ false);
  448. if (IsReserved(name)) {
  449. name = "pb_" + name;
  450. }
  451. return name;
  452. }
  453. std::string JSByteGetterSuffix(BytesMode bytes_mode) {
  454. switch (bytes_mode) {
  455. case BYTES_DEFAULT:
  456. return "";
  457. case BYTES_B64:
  458. return "B64";
  459. case BYTES_U8:
  460. return "U8";
  461. default:
  462. assert(false);
  463. }
  464. return "";
  465. }
  466. // Returns the field name as a capitalized portion of a getter/setter method
  467. // name, e.g. MyField for .getMyField().
  468. std::string JSGetterName(const GeneratorOptions& options,
  469. const FieldDescriptor* field,
  470. BytesMode bytes_mode = BYTES_DEFAULT,
  471. bool drop_list = false) {
  472. std::string name = JSIdent(options, field,
  473. /* is_upper_camel = */ true,
  474. /* is_map = */ false, drop_list);
  475. if (field->type() == FieldDescriptor::TYPE_BYTES) {
  476. std::string suffix = JSByteGetterSuffix(bytes_mode);
  477. if (!suffix.empty()) {
  478. name += "_as" + suffix;
  479. }
  480. }
  481. if (name == "Extension" || name == "JsPbMessageId") {
  482. // Avoid conflicts with base-class names.
  483. name += "$";
  484. }
  485. return name;
  486. }
  487. std::string JSOneofName(const OneofDescriptor* oneof) {
  488. return ToUpperCamel(ParseLowerUnderscore(oneof->name()));
  489. }
  490. // Returns the index corresponding to this field in the JSPB array (underlying
  491. // data storage array).
  492. std::string JSFieldIndex(const FieldDescriptor* field) {
  493. // Determine whether this field is a member of a group. Group fields are a bit
  494. // wonky: their "containing type" is a message type created just for the
  495. // group, and that type's parent type has a field with the group-message type
  496. // as its message type and TYPE_GROUP as its field type. For such fields, the
  497. // index we use is relative to the field number of the group submessage field.
  498. // For all other fields, we just use the field number.
  499. const Descriptor* containing_type = field->containing_type();
  500. const Descriptor* parent_type = containing_type->containing_type();
  501. if (parent_type != NULL) {
  502. for (int i = 0; i < parent_type->field_count(); i++) {
  503. if (parent_type->field(i)->type() == FieldDescriptor::TYPE_GROUP &&
  504. parent_type->field(i)->message_type() == containing_type) {
  505. return StrCat(field->number() - parent_type->field(i)->number());
  506. }
  507. }
  508. }
  509. return StrCat(field->number());
  510. }
  511. std::string JSOneofIndex(const OneofDescriptor* oneof) {
  512. int index = -1;
  513. for (int i = 0; i < oneof->containing_type()->oneof_decl_count(); i++) {
  514. const OneofDescriptor* o = oneof->containing_type()->oneof_decl(i);
  515. if (o->is_synthetic()) continue;
  516. // If at least one field in this oneof is not JSPB-ignored, count the oneof.
  517. for (int j = 0; j < o->field_count(); j++) {
  518. const FieldDescriptor* f = o->field(j);
  519. if (!IgnoreField(f)) {
  520. index++;
  521. break; // inner loop
  522. }
  523. }
  524. if (o == oneof) {
  525. break;
  526. }
  527. }
  528. return StrCat(index);
  529. }
  530. // Decodes a codepoint in \x0000 -- \xFFFF.
  531. uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
  532. if (*length == 0) {
  533. return 0;
  534. }
  535. size_t expected = 0;
  536. if ((*bytes & 0x80) == 0) {
  537. expected = 1;
  538. } else if ((*bytes & 0xe0) == 0xc0) {
  539. expected = 2;
  540. } else if ((*bytes & 0xf0) == 0xe0) {
  541. expected = 3;
  542. } else {
  543. // Too long -- don't accept.
  544. *length = 0;
  545. return 0;
  546. }
  547. if (*length < expected) {
  548. // Not enough bytes -- don't accept.
  549. *length = 0;
  550. return 0;
  551. }
  552. *length = expected;
  553. switch (expected) {
  554. case 1:
  555. return bytes[0];
  556. case 2:
  557. return ((bytes[0] & 0x1F) << 6) | ((bytes[1] & 0x3F) << 0);
  558. case 3:
  559. return ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) |
  560. ((bytes[2] & 0x3F) << 0);
  561. default:
  562. return 0;
  563. }
  564. }
  565. // Escapes the contents of a string to be included within double-quotes ("") in
  566. // JavaScript. The input data should be a UTF-8 encoded C++ string of chars.
  567. // Returns false if |out| was truncated because |in| contained invalid UTF-8 or
  568. // codepoints outside the BMP.
  569. // TODO(b/115551870): Support codepoints outside the BMP.
  570. bool EscapeJSString(const std::string& in, std::string* out) {
  571. size_t decoded = 0;
  572. for (size_t i = 0; i < in.size(); i += decoded) {
  573. uint16 codepoint = 0;
  574. // Decode the next UTF-8 codepoint.
  575. size_t have_bytes = in.size() - i;
  576. uint8 bytes[3] = {
  577. static_cast<uint8>(in[i]),
  578. static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0),
  579. static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0),
  580. };
  581. codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
  582. if (have_bytes == 0) {
  583. return false;
  584. }
  585. decoded = have_bytes;
  586. switch (codepoint) {
  587. case '\'':
  588. *out += "\\x27";
  589. break;
  590. case '"':
  591. *out += "\\x22";
  592. break;
  593. case '<':
  594. *out += "\\x3c";
  595. break;
  596. case '=':
  597. *out += "\\x3d";
  598. break;
  599. case '>':
  600. *out += "\\x3e";
  601. break;
  602. case '&':
  603. *out += "\\x26";
  604. break;
  605. case '\b':
  606. *out += "\\b";
  607. break;
  608. case '\t':
  609. *out += "\\t";
  610. break;
  611. case '\n':
  612. *out += "\\n";
  613. break;
  614. case '\f':
  615. *out += "\\f";
  616. break;
  617. case '\r':
  618. *out += "\\r";
  619. break;
  620. case '\\':
  621. *out += "\\\\";
  622. break;
  623. default:
  624. // TODO(b/115551870): Once we're supporting codepoints outside the BMP,
  625. // use a single Unicode codepoint escape if the output language is
  626. // ECMAScript 2015 or above. Otherwise, use a surrogate pair.
  627. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals
  628. if (codepoint >= 0x20 && codepoint <= 0x7e) {
  629. *out += static_cast<char>(codepoint);
  630. } else if (codepoint >= 0x100) {
  631. *out += StringPrintf("\\u%04x", codepoint);
  632. } else {
  633. *out += StringPrintf("\\x%02x", codepoint);
  634. }
  635. break;
  636. }
  637. }
  638. return true;
  639. }
  640. std::string EscapeBase64(const std::string& in) {
  641. static const char* kAlphabet =
  642. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  643. std::string result;
  644. for (size_t i = 0; i < in.size(); i += 3) {
  645. int value = (in[i] << 16) | (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) |
  646. (((i + 2) < in.size()) ? (in[i + 2] << 0) : 0);
  647. result += kAlphabet[(value >> 18) & 0x3f];
  648. result += kAlphabet[(value >> 12) & 0x3f];
  649. if ((i + 1) < in.size()) {
  650. result += kAlphabet[(value >> 6) & 0x3f];
  651. } else {
  652. result += '=';
  653. }
  654. if ((i + 2) < in.size()) {
  655. result += kAlphabet[(value >> 0) & 0x3f];
  656. } else {
  657. result += '=';
  658. }
  659. }
  660. return result;
  661. }
  662. // Post-process the result of SimpleFtoa/SimpleDtoa to *exactly* match the
  663. // original codegen's formatting (which is just .toString() on java.lang.Double
  664. // or java.lang.Float).
  665. std::string PostProcessFloat(std::string result) {
  666. // If inf, -inf or nan, replace with +Infinity, -Infinity or NaN.
  667. if (result == "inf") {
  668. return "Infinity";
  669. } else if (result == "-inf") {
  670. return "-Infinity";
  671. } else if (result == "nan") {
  672. return "NaN";
  673. }
  674. // If scientific notation (e.g., "1e10"), (i) capitalize the "e", (ii)
  675. // ensure that the mantissa (portion prior to the "e") has at least one
  676. // fractional digit (after the decimal point), and (iii) strip any unnecessary
  677. // leading zeroes and/or '+' signs from the exponent.
  678. std::string::size_type exp_pos = result.find('e');
  679. if (exp_pos != std::string::npos) {
  680. std::string mantissa = result.substr(0, exp_pos);
  681. std::string exponent = result.substr(exp_pos + 1);
  682. // Add ".0" to mantissa if no fractional part exists.
  683. if (mantissa.find('.') == std::string::npos) {
  684. mantissa += ".0";
  685. }
  686. // Strip the sign off the exponent and store as |exp_neg|.
  687. bool exp_neg = false;
  688. if (!exponent.empty() && exponent[0] == '+') {
  689. exponent = exponent.substr(1);
  690. } else if (!exponent.empty() && exponent[0] == '-') {
  691. exp_neg = true;
  692. exponent = exponent.substr(1);
  693. }
  694. // Strip any leading zeroes off the exponent.
  695. while (exponent.size() > 1 && exponent[0] == '0') {
  696. exponent = exponent.substr(1);
  697. }
  698. return mantissa + "E" + std::string(exp_neg ? "-" : "") + exponent;
  699. }
  700. // Otherwise, this is an ordinary decimal number. Append ".0" if result has no
  701. // decimal/fractional part in order to match output of original codegen.
  702. if (result.find('.') == std::string::npos) {
  703. result += ".0";
  704. }
  705. return result;
  706. }
  707. std::string FloatToString(float value) {
  708. std::string result = SimpleFtoa(value);
  709. return PostProcessFloat(result);
  710. }
  711. std::string DoubleToString(double value) {
  712. std::string result = SimpleDtoa(value);
  713. return PostProcessFloat(result);
  714. }
  715. bool InRealOneof(const FieldDescriptor* field) {
  716. return field->containing_oneof() &&
  717. !field->containing_oneof()->is_synthetic();
  718. }
  719. // Return true if this is an integral field that should be represented as string
  720. // in JS.
  721. bool IsIntegralFieldWithStringJSType(const FieldDescriptor* field) {
  722. switch (field->cpp_type()) {
  723. case FieldDescriptor::CPPTYPE_INT64:
  724. case FieldDescriptor::CPPTYPE_UINT64:
  725. // The default value of JSType is JS_NORMAL, which behaves the same as
  726. // JS_NUMBER.
  727. return field->options().jstype() == FieldOptions::JS_STRING;
  728. default:
  729. return false;
  730. }
  731. }
  732. std::string MaybeNumberString(const FieldDescriptor* field,
  733. const std::string& orig) {
  734. return IsIntegralFieldWithStringJSType(field) ? ("\"" + orig + "\"") : orig;
  735. }
  736. std::string JSFieldDefault(const FieldDescriptor* field) {
  737. if (field->is_repeated()) {
  738. return "[]";
  739. }
  740. switch (field->cpp_type()) {
  741. case FieldDescriptor::CPPTYPE_INT32:
  742. return MaybeNumberString(field, StrCat(field->default_value_int32()));
  743. case FieldDescriptor::CPPTYPE_UINT32:
  744. // The original codegen is in Java, and Java protobufs store unsigned
  745. // integer values as signed integer values. In order to exactly match the
  746. // output, we need to reinterpret as base-2 signed. Ugh.
  747. return MaybeNumberString(
  748. field, StrCat(static_cast<int32>(field->default_value_uint32())));
  749. case FieldDescriptor::CPPTYPE_INT64:
  750. return MaybeNumberString(field, StrCat(field->default_value_int64()));
  751. case FieldDescriptor::CPPTYPE_UINT64:
  752. // See above note for uint32 -- reinterpreting as signed.
  753. return MaybeNumberString(
  754. field, StrCat(static_cast<int64>(field->default_value_uint64())));
  755. case FieldDescriptor::CPPTYPE_ENUM:
  756. return StrCat(field->default_value_enum()->number());
  757. case FieldDescriptor::CPPTYPE_BOOL:
  758. return field->default_value_bool() ? "true" : "false";
  759. case FieldDescriptor::CPPTYPE_FLOAT:
  760. return FloatToString(field->default_value_float());
  761. case FieldDescriptor::CPPTYPE_DOUBLE:
  762. return DoubleToString(field->default_value_double());
  763. case FieldDescriptor::CPPTYPE_STRING:
  764. if (field->type() == FieldDescriptor::TYPE_STRING) {
  765. std::string out;
  766. bool is_valid = EscapeJSString(field->default_value_string(), &out);
  767. if (!is_valid) {
  768. // TODO(b/115551870): Decide whether this should be a hard error.
  769. GOOGLE_LOG(WARNING)
  770. << "The default value for field " << field->full_name()
  771. << " was truncated since it contained invalid UTF-8 or"
  772. " codepoints outside the basic multilingual plane.";
  773. }
  774. return "\"" + out + "\"";
  775. } else { // Bytes
  776. return "\"" + EscapeBase64(field->default_value_string()) + "\"";
  777. }
  778. case FieldDescriptor::CPPTYPE_MESSAGE:
  779. return "null";
  780. }
  781. GOOGLE_LOG(FATAL) << "Shouldn't reach here.";
  782. return "";
  783. }
  784. std::string ProtoTypeName(const GeneratorOptions& options,
  785. const FieldDescriptor* field) {
  786. switch (field->type()) {
  787. case FieldDescriptor::TYPE_BOOL:
  788. return "bool";
  789. case FieldDescriptor::TYPE_INT32:
  790. return "int32";
  791. case FieldDescriptor::TYPE_UINT32:
  792. return "uint32";
  793. case FieldDescriptor::TYPE_SINT32:
  794. return "sint32";
  795. case FieldDescriptor::TYPE_FIXED32:
  796. return "fixed32";
  797. case FieldDescriptor::TYPE_SFIXED32:
  798. return "sfixed32";
  799. case FieldDescriptor::TYPE_INT64:
  800. return "int64";
  801. case FieldDescriptor::TYPE_UINT64:
  802. return "uint64";
  803. case FieldDescriptor::TYPE_SINT64:
  804. return "sint64";
  805. case FieldDescriptor::TYPE_FIXED64:
  806. return "fixed64";
  807. case FieldDescriptor::TYPE_SFIXED64:
  808. return "sfixed64";
  809. case FieldDescriptor::TYPE_FLOAT:
  810. return "float";
  811. case FieldDescriptor::TYPE_DOUBLE:
  812. return "double";
  813. case FieldDescriptor::TYPE_STRING:
  814. return "string";
  815. case FieldDescriptor::TYPE_BYTES:
  816. return "bytes";
  817. case FieldDescriptor::TYPE_GROUP:
  818. return GetMessagePath(options, field->message_type());
  819. case FieldDescriptor::TYPE_ENUM:
  820. return GetEnumPath(options, field->enum_type());
  821. case FieldDescriptor::TYPE_MESSAGE:
  822. return GetMessagePath(options, field->message_type());
  823. default:
  824. return "";
  825. }
  826. }
  827. std::string JSIntegerTypeName(const FieldDescriptor* field) {
  828. return IsIntegralFieldWithStringJSType(field) ? "string" : "number";
  829. }
  830. std::string JSStringTypeName(const GeneratorOptions& options,
  831. const FieldDescriptor* field,
  832. BytesMode bytes_mode) {
  833. if (field->type() == FieldDescriptor::TYPE_BYTES) {
  834. switch (bytes_mode) {
  835. case BYTES_DEFAULT:
  836. return "(string|Uint8Array)";
  837. case BYTES_B64:
  838. return "string";
  839. case BYTES_U8:
  840. return "Uint8Array";
  841. default:
  842. assert(false);
  843. }
  844. }
  845. return "string";
  846. }
  847. std::string JSTypeName(const GeneratorOptions& options,
  848. const FieldDescriptor* field, BytesMode bytes_mode) {
  849. switch (field->cpp_type()) {
  850. case FieldDescriptor::CPPTYPE_BOOL:
  851. return "boolean";
  852. case FieldDescriptor::CPPTYPE_INT32:
  853. return JSIntegerTypeName(field);
  854. case FieldDescriptor::CPPTYPE_INT64:
  855. return JSIntegerTypeName(field);
  856. case FieldDescriptor::CPPTYPE_UINT32:
  857. return JSIntegerTypeName(field);
  858. case FieldDescriptor::CPPTYPE_UINT64:
  859. return JSIntegerTypeName(field);
  860. case FieldDescriptor::CPPTYPE_FLOAT:
  861. return "number";
  862. case FieldDescriptor::CPPTYPE_DOUBLE:
  863. return "number";
  864. case FieldDescriptor::CPPTYPE_STRING:
  865. return JSStringTypeName(options, field, bytes_mode);
  866. case FieldDescriptor::CPPTYPE_ENUM:
  867. return GetEnumPath(options, field->enum_type());
  868. case FieldDescriptor::CPPTYPE_MESSAGE:
  869. return GetMessagePath(options, field->message_type());
  870. default:
  871. return "";
  872. }
  873. }
  874. // Used inside Google only -- do not remove.
  875. bool UseBrokenPresenceSemantics(const GeneratorOptions& options,
  876. const FieldDescriptor* field) {
  877. return false;
  878. }
  879. // Returns true for fields that return "null" from accessors when they are
  880. // unset. This should normally only be true for non-repeated submessages, but we
  881. // have legacy users who relied on old behavior where accessors behaved this
  882. // way.
  883. bool ReturnsNullWhenUnset(const GeneratorOptions& options,
  884. const FieldDescriptor* field) {
  885. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
  886. field->is_optional()) {
  887. return true;
  888. }
  889. // TODO(haberman): remove this case and unconditionally return false.
  890. return UseBrokenPresenceSemantics(options, field) && !field->is_repeated() &&
  891. !field->has_default_value();
  892. }
  893. // In a sane world, this would be the same as ReturnsNullWhenUnset(). But in
  894. // the status quo, some fields declare that they never return null/undefined
  895. // even though they actually do:
  896. // * required fields
  897. // * optional enum fields
  898. // * proto3 primitive fields.
  899. bool DeclaredReturnTypeIsNullable(const GeneratorOptions& options,
  900. const FieldDescriptor* field) {
  901. if (field->is_required() || field->type() == FieldDescriptor::TYPE_ENUM) {
  902. return false;
  903. }
  904. if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
  905. field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
  906. return false;
  907. }
  908. return ReturnsNullWhenUnset(options, field);
  909. }
  910. bool SetterAcceptsUndefined(const GeneratorOptions& options,
  911. const FieldDescriptor* field) {
  912. if (ReturnsNullWhenUnset(options, field)) {
  913. return true;
  914. }
  915. // Broken presence semantics always accepts undefined for setters.
  916. return UseBrokenPresenceSemantics(options, field);
  917. }
  918. bool SetterAcceptsNull(const GeneratorOptions& options,
  919. const FieldDescriptor* field) {
  920. if (ReturnsNullWhenUnset(options, field)) {
  921. return true;
  922. }
  923. // With broken presence semantics, fields with defaults accept "null" for
  924. // setters, but other fields do not. This is a strange quirk of the old
  925. // codegen.
  926. return UseBrokenPresenceSemantics(options, field) &&
  927. field->has_default_value();
  928. }
  929. // Returns types which are known to by non-nullable by default.
  930. // The style guide requires that we omit "!" in this case.
  931. bool IsPrimitive(const std::string& type) {
  932. return type == "undefined" || type == "string" || type == "number" ||
  933. type == "boolean";
  934. }
  935. std::string JSFieldTypeAnnotation(const GeneratorOptions& options,
  936. const FieldDescriptor* field,
  937. bool is_setter_argument, bool force_present,
  938. bool singular_if_not_packed,
  939. BytesMode bytes_mode = BYTES_DEFAULT,
  940. bool force_singular = false) {
  941. std::string jstype = JSTypeName(options, field, bytes_mode);
  942. if (!force_singular && field->is_repeated() &&
  943. (field->is_packed() || !singular_if_not_packed)) {
  944. if (field->type() == FieldDescriptor::TYPE_BYTES &&
  945. bytes_mode == BYTES_DEFAULT) {
  946. jstype = "(Array<!Uint8Array>|Array<string>)";
  947. } else {
  948. if (!IsPrimitive(jstype)) {
  949. jstype = "!" + jstype;
  950. }
  951. jstype = "Array<" + jstype + ">";
  952. }
  953. }
  954. bool is_null_or_undefined = false;
  955. if (is_setter_argument) {
  956. if (SetterAcceptsNull(options, field)) {
  957. jstype = "?" + jstype;
  958. is_null_or_undefined = true;
  959. }
  960. if (SetterAcceptsUndefined(options, field)) {
  961. jstype += "|undefined";
  962. is_null_or_undefined = true;
  963. }
  964. } else if (force_present) {
  965. // Don't add null or undefined.
  966. } else {
  967. if (DeclaredReturnTypeIsNullable(options, field)) {
  968. jstype = "?" + jstype;
  969. is_null_or_undefined = true;
  970. }
  971. }
  972. if (!is_null_or_undefined && !IsPrimitive(jstype)) {
  973. jstype = "!" + jstype;
  974. }
  975. return jstype;
  976. }
  977. std::string JSBinaryReaderMethodType(const FieldDescriptor* field) {
  978. std::string name = field->type_name();
  979. if (name[0] >= 'a' && name[0] <= 'z') {
  980. name[0] = (name[0] - 'a') + 'A';
  981. }
  982. return IsIntegralFieldWithStringJSType(field) ? (name + "String") : name;
  983. }
  984. std::string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
  985. bool is_writer) {
  986. std::string name = JSBinaryReaderMethodType(field);
  987. if (field->is_packed()) {
  988. name = "Packed" + name;
  989. } else if (is_writer && field->is_repeated()) {
  990. name = "Repeated" + name;
  991. }
  992. return name;
  993. }
  994. std::string JSBinaryReaderMethodName(const GeneratorOptions& options,
  995. const FieldDescriptor* field) {
  996. return "jspb.BinaryReader.prototype.read" +
  997. JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
  998. }
  999. std::string JSBinaryWriterMethodName(const GeneratorOptions& options,
  1000. const FieldDescriptor* field) {
  1001. if (field->containing_type() &&
  1002. field->containing_type()->options().message_set_wire_format()) {
  1003. return "jspb.BinaryWriter.prototype.writeMessageSet";
  1004. }
  1005. return "jspb.BinaryWriter.prototype.write" +
  1006. JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
  1007. }
  1008. std::string JSTypeTag(const FieldDescriptor* desc) {
  1009. switch (desc->type()) {
  1010. case FieldDescriptor::TYPE_DOUBLE:
  1011. case FieldDescriptor::TYPE_FLOAT:
  1012. return "Float";
  1013. case FieldDescriptor::TYPE_INT32:
  1014. case FieldDescriptor::TYPE_UINT32:
  1015. case FieldDescriptor::TYPE_INT64:
  1016. case FieldDescriptor::TYPE_UINT64:
  1017. case FieldDescriptor::TYPE_FIXED32:
  1018. case FieldDescriptor::TYPE_FIXED64:
  1019. case FieldDescriptor::TYPE_SINT32:
  1020. case FieldDescriptor::TYPE_SINT64:
  1021. case FieldDescriptor::TYPE_SFIXED32:
  1022. case FieldDescriptor::TYPE_SFIXED64:
  1023. if (IsIntegralFieldWithStringJSType(desc)) {
  1024. return "StringInt";
  1025. } else {
  1026. return "Int";
  1027. }
  1028. case FieldDescriptor::TYPE_BOOL:
  1029. return "Boolean";
  1030. case FieldDescriptor::TYPE_STRING:
  1031. return "String";
  1032. case FieldDescriptor::TYPE_BYTES:
  1033. return "Bytes";
  1034. case FieldDescriptor::TYPE_ENUM:
  1035. return "Enum";
  1036. default:
  1037. assert(false);
  1038. }
  1039. return "";
  1040. }
  1041. bool HasRepeatedFields(const GeneratorOptions& options,
  1042. const Descriptor* desc) {
  1043. for (int i = 0; i < desc->field_count(); i++) {
  1044. if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
  1045. return true;
  1046. }
  1047. }
  1048. return false;
  1049. }
  1050. static const char* kRepeatedFieldArrayName = ".repeatedFields_";
  1051. std::string RepeatedFieldsArrayName(const GeneratorOptions& options,
  1052. const Descriptor* desc) {
  1053. return HasRepeatedFields(options, desc)
  1054. ? (GetMessagePath(options, desc) + kRepeatedFieldArrayName)
  1055. : "null";
  1056. }
  1057. bool HasOneofFields(const Descriptor* desc) {
  1058. for (int i = 0; i < desc->field_count(); i++) {
  1059. if (InRealOneof(desc->field(i))) {
  1060. return true;
  1061. }
  1062. }
  1063. return false;
  1064. }
  1065. static const char* kOneofGroupArrayName = ".oneofGroups_";
  1066. std::string OneofFieldsArrayName(const GeneratorOptions& options,
  1067. const Descriptor* desc) {
  1068. return HasOneofFields(desc)
  1069. ? (GetMessagePath(options, desc) + kOneofGroupArrayName)
  1070. : "null";
  1071. }
  1072. std::string RepeatedFieldNumberList(const GeneratorOptions& options,
  1073. const Descriptor* desc) {
  1074. std::vector<std::string> numbers;
  1075. for (int i = 0; i < desc->field_count(); i++) {
  1076. if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
  1077. numbers.push_back(JSFieldIndex(desc->field(i)));
  1078. }
  1079. }
  1080. return "[" + Join(numbers, ",") + "]";
  1081. }
  1082. std::string OneofGroupList(const Descriptor* desc) {
  1083. // List of arrays (one per oneof), each of which is a list of field indices
  1084. std::vector<std::string> oneof_entries;
  1085. for (int i = 0; i < desc->oneof_decl_count(); i++) {
  1086. const OneofDescriptor* oneof = desc->oneof_decl(i);
  1087. if (IgnoreOneof(oneof)) {
  1088. continue;
  1089. }
  1090. std::vector<std::string> oneof_fields;
  1091. for (int j = 0; j < oneof->field_count(); j++) {
  1092. if (IgnoreField(oneof->field(j))) {
  1093. continue;
  1094. }
  1095. oneof_fields.push_back(JSFieldIndex(oneof->field(j)));
  1096. }
  1097. oneof_entries.push_back("[" + Join(oneof_fields, ",") + "]");
  1098. }
  1099. return "[" + Join(oneof_entries, ",") + "]";
  1100. }
  1101. std::string JSOneofArray(const GeneratorOptions& options,
  1102. const FieldDescriptor* field) {
  1103. return OneofFieldsArrayName(options, field->containing_type()) + "[" +
  1104. JSOneofIndex(field->containing_oneof()) + "]";
  1105. }
  1106. std::string RelativeTypeName(const FieldDescriptor* field) {
  1107. assert(field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM ||
  1108. field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
  1109. // For a field with an enum or message type, compute a name relative to the
  1110. // path name of the message type containing this field.
  1111. std::string package = field->file()->package();
  1112. std::string containing_type = field->containing_type()->full_name() + ".";
  1113. std::string type = (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM)
  1114. ? field->enum_type()->full_name()
  1115. : field->message_type()->full_name();
  1116. // |prefix| is advanced as we find separators '.' past the common package
  1117. // prefix that yield common prefixes in the containing type's name and this
  1118. // type's name.
  1119. int prefix = 0;
  1120. for (int i = 0; i < type.size() && i < containing_type.size(); i++) {
  1121. if (type[i] != containing_type[i]) {
  1122. break;
  1123. }
  1124. if (type[i] == '.' && i >= package.size()) {
  1125. prefix = i + 1;
  1126. }
  1127. }
  1128. return type.substr(prefix);
  1129. }
  1130. std::string JSExtensionsObjectName(const GeneratorOptions& options,
  1131. const FileDescriptor* from_file,
  1132. const Descriptor* desc) {
  1133. if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
  1134. // TODO(haberman): fix this for the kImportCommonJs case.
  1135. return "jspb.Message.messageSetExtensions";
  1136. } else {
  1137. return MaybeCrossFileRef(options, from_file, desc) + ".extensions";
  1138. }
  1139. }
  1140. static const int kMapKeyField = 1;
  1141. static const int kMapValueField = 2;
  1142. const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) {
  1143. assert(field->is_map());
  1144. return field->message_type()->FindFieldByNumber(kMapKeyField);
  1145. }
  1146. const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) {
  1147. assert(field->is_map());
  1148. return field->message_type()->FindFieldByNumber(kMapValueField);
  1149. }
  1150. std::string FieldDefinition(const GeneratorOptions& options,
  1151. const FieldDescriptor* field) {
  1152. if (field->is_map()) {
  1153. const FieldDescriptor* key_field = MapFieldKey(field);
  1154. const FieldDescriptor* value_field = MapFieldValue(field);
  1155. std::string key_type = ProtoTypeName(options, key_field);
  1156. std::string value_type;
  1157. if (value_field->type() == FieldDescriptor::TYPE_ENUM ||
  1158. value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
  1159. value_type = RelativeTypeName(value_field);
  1160. } else {
  1161. value_type = ProtoTypeName(options, value_field);
  1162. }
  1163. return StringPrintf("map<%s, %s> %s = %d;", key_type.c_str(),
  1164. value_type.c_str(), field->name().c_str(),
  1165. field->number());
  1166. } else {
  1167. std::string qualifier =
  1168. field->is_repeated() ? "repeated"
  1169. : (field->is_optional() ? "optional" : "required");
  1170. std::string type, name;
  1171. if (field->type() == FieldDescriptor::TYPE_ENUM ||
  1172. field->type() == FieldDescriptor::TYPE_MESSAGE) {
  1173. type = RelativeTypeName(field);
  1174. name = field->name();
  1175. } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
  1176. type = "group";
  1177. name = field->message_type()->name();
  1178. } else {
  1179. type = ProtoTypeName(options, field);
  1180. name = field->name();
  1181. }
  1182. return StringPrintf("%s %s %s = %d;", qualifier.c_str(), type.c_str(),
  1183. name.c_str(), field->number());
  1184. }
  1185. }
  1186. std::string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
  1187. std::string comments;
  1188. if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) {
  1189. comments +=
  1190. " * Note that Uint8Array is not supported on all browsers.\n"
  1191. " * @see http://caniuse.com/Uint8Array\n";
  1192. }
  1193. return comments;
  1194. }
  1195. bool ShouldGenerateExtension(const FieldDescriptor* field) {
  1196. return field->is_extension() && !IgnoreField(field);
  1197. }
  1198. bool HasExtensions(const Descriptor* desc) {
  1199. for (int i = 0; i < desc->extension_count(); i++) {
  1200. if (ShouldGenerateExtension(desc->extension(i))) {
  1201. return true;
  1202. }
  1203. }
  1204. for (int i = 0; i < desc->nested_type_count(); i++) {
  1205. if (HasExtensions(desc->nested_type(i))) {
  1206. return true;
  1207. }
  1208. }
  1209. return false;
  1210. }
  1211. bool HasExtensions(const FileDescriptor* file) {
  1212. for (int i = 0; i < file->extension_count(); i++) {
  1213. if (ShouldGenerateExtension(file->extension(i))) {
  1214. return true;
  1215. }
  1216. }
  1217. for (int i = 0; i < file->message_type_count(); i++) {
  1218. if (HasExtensions(file->message_type(i))) {
  1219. return true;
  1220. }
  1221. }
  1222. return false;
  1223. }
  1224. bool HasMap(const GeneratorOptions& options, const Descriptor* desc) {
  1225. for (int i = 0; i < desc->field_count(); i++) {
  1226. if (desc->field(i)->is_map()) {
  1227. return true;
  1228. }
  1229. }
  1230. for (int i = 0; i < desc->nested_type_count(); i++) {
  1231. if (HasMap(options, desc->nested_type(i))) {
  1232. return true;
  1233. }
  1234. }
  1235. return false;
  1236. }
  1237. bool FileHasMap(const GeneratorOptions& options, const FileDescriptor* desc) {
  1238. for (int i = 0; i < desc->message_type_count(); i++) {
  1239. if (HasMap(options, desc->message_type(i))) {
  1240. return true;
  1241. }
  1242. }
  1243. return false;
  1244. }
  1245. bool IsExtendable(const Descriptor* desc) {
  1246. return desc->extension_range_count() > 0;
  1247. }
  1248. // Returns the max index in the underlying data storage array beyond which the
  1249. // extension object is used.
  1250. std::string GetPivot(const Descriptor* desc) {
  1251. static const int kDefaultPivot = 500;
  1252. // Find the max field number
  1253. int max_field_number = 0;
  1254. for (int i = 0; i < desc->field_count(); i++) {
  1255. if (!IgnoreField(desc->field(i)) &&
  1256. desc->field(i)->number() > max_field_number) {
  1257. max_field_number = desc->field(i)->number();
  1258. }
  1259. }
  1260. int pivot = -1;
  1261. if (IsExtendable(desc) || (max_field_number >= kDefaultPivot)) {
  1262. pivot = ((max_field_number + 1) < kDefaultPivot) ? (max_field_number + 1)
  1263. : kDefaultPivot;
  1264. }
  1265. return StrCat(pivot);
  1266. }
  1267. // Whether this field represents presence. For fields with presence, we
  1268. // generate extra methods (clearFoo() and hasFoo()) for this field.
  1269. bool HasFieldPresence(const GeneratorOptions& options,
  1270. const FieldDescriptor* field) {
  1271. // This returns false for repeated fields and maps, but we still do
  1272. // generate clearFoo() methods for these through a special case elsewhere.
  1273. return field->has_presence();
  1274. }
  1275. // We use this to implement the semantics that same file can be generated
  1276. // multiple times, but only the last one keep the short name. Others all use
  1277. // long name with extra information to distinguish (For message and enum, the
  1278. // extra information is package name, for file level extension, the extra
  1279. // information is proto's filename).
  1280. // We never actually write the files, but we keep a set of which descriptors
  1281. // were the final one for a given filename.
  1282. class FileDeduplicator {
  1283. public:
  1284. explicit FileDeduplicator(const GeneratorOptions& options)
  1285. : error_on_conflict_(options.error_on_name_conflict) {}
  1286. // params:
  1287. // filenames: a pair of {short filename, full filename}
  1288. // (short filename don't have extra information, full filename
  1289. // contains extra information)
  1290. // desc: The Descriptor or SCC pointer or EnumDescriptor.
  1291. // error: The returned error information.
  1292. bool AddFile(const std::pair<std::string, std::string> filenames,
  1293. const void* desc, std::string* error) {
  1294. if (descs_by_shortname_.find(filenames.first) !=
  1295. descs_by_shortname_.end()) {
  1296. if (error_on_conflict_) {
  1297. *error = "Name conflict: file name " + filenames.first +
  1298. " would be generated by two descriptors";
  1299. return false;
  1300. }
  1301. // Change old pointer's actual name to full name.
  1302. auto short_name_desc = descs_by_shortname_[filenames.first];
  1303. allowed_descs_actual_name_[short_name_desc] =
  1304. allowed_descs_full_name_[short_name_desc];
  1305. }
  1306. descs_by_shortname_[filenames.first] = desc;
  1307. allowed_descs_actual_name_[desc] = filenames.first;
  1308. allowed_descs_full_name_[desc] = filenames.second;
  1309. return true;
  1310. }
  1311. void GetAllowedMap(std::map<const void*, std::string>* allowed_set) {
  1312. *allowed_set = allowed_descs_actual_name_;
  1313. }
  1314. private:
  1315. bool error_on_conflict_;
  1316. // The map that restores all the descs that are using short name as filename.
  1317. std::map<std::string, const void*> descs_by_shortname_;
  1318. // The final actual filename map.
  1319. std::map<const void*, std::string> allowed_descs_actual_name_;
  1320. // The full name map.
  1321. std::map<const void*, std::string> allowed_descs_full_name_;
  1322. };
  1323. void DepthFirstSearch(const FileDescriptor* file,
  1324. std::vector<const FileDescriptor*>* list,
  1325. std::set<const FileDescriptor*>* seen) {
  1326. if (!seen->insert(file).second) {
  1327. return;
  1328. }
  1329. // Add all dependencies.
  1330. for (int i = 0; i < file->dependency_count(); i++) {
  1331. DepthFirstSearch(file->dependency(i), list, seen);
  1332. }
  1333. // Add this file.
  1334. list->push_back(file);
  1335. }
  1336. // A functor for the predicate to remove_if() below. Returns true if a given
  1337. // FileDescriptor is not in the given set.
  1338. class NotInSet {
  1339. public:
  1340. explicit NotInSet(const std::set<const FileDescriptor*>& file_set)
  1341. : file_set_(file_set) {}
  1342. bool operator()(const FileDescriptor* file) {
  1343. return file_set_.count(file) == 0;
  1344. }
  1345. private:
  1346. const std::set<const FileDescriptor*>& file_set_;
  1347. };
  1348. // This function generates an ordering of the input FileDescriptors that matches
  1349. // the logic of the old code generator. The order is significant because two
  1350. // different input files can generate the same output file, and the last one
  1351. // needs to win.
  1352. void GenerateJspbFileOrder(const std::vector<const FileDescriptor*>& input,
  1353. std::vector<const FileDescriptor*>* ordered) {
  1354. // First generate an ordering of all reachable files (including dependencies)
  1355. // with depth-first search. This mimics the behavior of --include_imports,
  1356. // which is what the old codegen used.
  1357. ordered->clear();
  1358. std::set<const FileDescriptor*> seen;
  1359. std::set<const FileDescriptor*> input_set;
  1360. for (int i = 0; i < input.size(); i++) {
  1361. DepthFirstSearch(input[i], ordered, &seen);
  1362. input_set.insert(input[i]);
  1363. }
  1364. // Now remove the entries that are not actually in our input list.
  1365. ordered->erase(
  1366. std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)),
  1367. ordered->end());
  1368. }
  1369. // If we're generating code in file-per-type mode, avoid overwriting files
  1370. // by choosing the last descriptor that writes each filename and permitting
  1371. // only those to generate code.
  1372. struct DepsGenerator {
  1373. std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
  1374. std::vector<const Descriptor*> deps;
  1375. auto maybe_add = [&](const Descriptor* d) {
  1376. if (d) deps.push_back(d);
  1377. };
  1378. for (int i = 0; i < desc->field_count(); i++) {
  1379. if (!IgnoreField(desc->field(i))) {
  1380. maybe_add(desc->field(i)->message_type());
  1381. }
  1382. }
  1383. for (int i = 0; i < desc->extension_count(); i++) {
  1384. maybe_add(desc->extension(i)->message_type());
  1385. maybe_add(desc->extension(i)->containing_type());
  1386. }
  1387. for (int i = 0; i < desc->nested_type_count(); i++) {
  1388. maybe_add(desc->nested_type(i));
  1389. }
  1390. maybe_add(desc->containing_type());
  1391. return deps;
  1392. }
  1393. };
  1394. bool GenerateJspbAllowedMap(const GeneratorOptions& options,
  1395. const std::vector<const FileDescriptor*>& files,
  1396. std::map<const void*, std::string>* allowed_set,
  1397. SCCAnalyzer<DepsGenerator>* analyzer,
  1398. std::string* error) {
  1399. std::vector<const FileDescriptor*> files_ordered;
  1400. GenerateJspbFileOrder(files, &files_ordered);
  1401. // Choose the last descriptor for each filename.
  1402. FileDeduplicator dedup(options);
  1403. std::set<const SCC*> added;
  1404. for (int i = 0; i < files_ordered.size(); i++) {
  1405. for (int j = 0; j < files_ordered[i]->message_type_count(); j++) {
  1406. const Descriptor* desc = files_ordered[i]->message_type(j);
  1407. if (added.insert(analyzer->GetSCC(desc)).second &&
  1408. !dedup.AddFile(
  1409. std::make_pair(
  1410. GetMessagesFileName(options, analyzer->GetSCC(desc), false),
  1411. GetMessagesFileName(options, analyzer->GetSCC(desc), true)),
  1412. analyzer->GetSCC(desc), error)) {
  1413. return false;
  1414. }
  1415. }
  1416. for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) {
  1417. const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
  1418. if (!dedup.AddFile(std::make_pair(GetEnumFileName(options, desc, false),
  1419. GetEnumFileName(options, desc, true)),
  1420. desc, error)) {
  1421. return false;
  1422. }
  1423. }
  1424. // Pull out all free-floating extensions and generate files for those too.
  1425. bool has_extension = false;
  1426. for (int j = 0; j < files_ordered[i]->extension_count(); j++) {
  1427. if (ShouldGenerateExtension(files_ordered[i]->extension(j))) {
  1428. has_extension = true;
  1429. }
  1430. }
  1431. if (has_extension) {
  1432. if (!dedup.AddFile(
  1433. std::make_pair(
  1434. GetExtensionFileName(options, files_ordered[i], false),
  1435. GetExtensionFileName(options, files_ordered[i], true)),
  1436. files_ordered[i], error)) {
  1437. return false;
  1438. }
  1439. }
  1440. }
  1441. dedup.GetAllowedMap(allowed_set);
  1442. return true;
  1443. }
  1444. // Embeds base64 encoded GeneratedCodeInfo proto in a comment at the end of
  1445. // file.
  1446. void EmbedCodeAnnotations(const GeneratedCodeInfo& annotations,
  1447. io::Printer* printer) {
  1448. // Serialize annotations proto into base64 string.
  1449. std::string meta_content;
  1450. annotations.SerializeToString(&meta_content);
  1451. std::string meta_64;
  1452. Base64Escape(meta_content, &meta_64);
  1453. // Print base64 encoded annotations at the end of output file in
  1454. // a comment.
  1455. printer->Print("\n// Below is base64 encoded GeneratedCodeInfo proto");
  1456. printer->Print("\n// $encoded_proto$\n", "encoded_proto", meta_64);
  1457. }
  1458. bool IsWellKnownTypeFile(const FileDescriptor* file) {
  1459. return HasPrefixString(file->name(), "google/protobuf/");
  1460. }
  1461. } // anonymous namespace
  1462. void Generator::GenerateHeader(const GeneratorOptions& options,
  1463. const FileDescriptor* file,
  1464. io::Printer* printer) const {
  1465. if (file != nullptr) {
  1466. printer->Print("// source: $filename$\n", "filename", file->name());
  1467. }
  1468. printer->Print(
  1469. "/**\n"
  1470. " * @fileoverview\n"
  1471. " * @enhanceable\n"
  1472. // TODO(b/152440355): requireType/requires diverged from internal version.
  1473. " * @suppress {missingRequire} reports error on implicit type usages.\n"
  1474. " * @suppress {messageConventions} JS Compiler reports an "
  1475. "error if a variable or\n"
  1476. " * field starts with 'MSG_' and isn't a translatable "
  1477. "message.\n"
  1478. " * @public\n"
  1479. " */\n"
  1480. "// GENERATED CODE -- DO NOT EDIT!\n"
  1481. "/* eslint-disable */\n"
  1482. "// @ts-nocheck\n"
  1483. "\n");
  1484. }
  1485. void Generator::FindProvidesForFile(const GeneratorOptions& options,
  1486. io::Printer* printer,
  1487. const FileDescriptor* file,
  1488. std::set<std::string>* provided) const {
  1489. for (int i = 0; i < file->message_type_count(); i++) {
  1490. FindProvidesForMessage(options, printer, file->message_type(i), provided);
  1491. }
  1492. for (int i = 0; i < file->enum_type_count(); i++) {
  1493. FindProvidesForEnum(options, printer, file->enum_type(i), provided);
  1494. }
  1495. }
  1496. void Generator::FindProvides(const GeneratorOptions& options,
  1497. io::Printer* printer,
  1498. const std::vector<const FileDescriptor*>& files,
  1499. std::set<std::string>* provided) const {
  1500. for (int i = 0; i < files.size(); i++) {
  1501. FindProvidesForFile(options, printer, files[i], provided);
  1502. }
  1503. printer->Print("\n");
  1504. }
  1505. void FindProvidesForOneOfEnum(const GeneratorOptions& options,
  1506. const OneofDescriptor* oneof,
  1507. std::set<std::string>* provided) {
  1508. std::string name = GetMessagePath(options, oneof->containing_type()) + "." +
  1509. JSOneofName(oneof) + "Case";
  1510. provided->insert(name);
  1511. }
  1512. void FindProvidesForOneOfEnums(const GeneratorOptions& options,
  1513. io::Printer* printer, const Descriptor* desc,
  1514. std::set<std::string>* provided) {
  1515. if (HasOneofFields(desc)) {
  1516. for (int i = 0; i < desc->oneof_decl_count(); i++) {
  1517. if (IgnoreOneof(desc->oneof_decl(i))) {
  1518. continue;
  1519. }
  1520. FindProvidesForOneOfEnum(options, desc->oneof_decl(i), provided);
  1521. }
  1522. }
  1523. }
  1524. void Generator::FindProvidesForMessage(const GeneratorOptions& options,
  1525. io::Printer* printer,
  1526. const Descriptor* desc,
  1527. std::set<std::string>* provided) const {
  1528. if (IgnoreMessage(desc)) {
  1529. return;
  1530. }
  1531. std::string name = GetMessagePath(options, desc);
  1532. provided->insert(name);
  1533. for (int i = 0; i < desc->enum_type_count(); i++) {
  1534. FindProvidesForEnum(options, printer, desc->enum_type(i), provided);
  1535. }
  1536. FindProvidesForOneOfEnums(options, printer, desc, provided);
  1537. for (int i = 0; i < desc->nested_type_count(); i++) {
  1538. FindProvidesForMessage(options, printer, desc->nested_type(i), provided);
  1539. }
  1540. }
  1541. void Generator::FindProvidesForEnum(const GeneratorOptions& options,
  1542. io::Printer* printer,
  1543. const EnumDescriptor* enumdesc,
  1544. std::set<std::string>* provided) const {
  1545. std::string name = GetEnumPath(options, enumdesc);
  1546. provided->insert(name);
  1547. }
  1548. void Generator::FindProvidesForFields(
  1549. const GeneratorOptions& options, io::Printer* printer,
  1550. const std::vector<const FieldDescriptor*>& fields,
  1551. std::set<std::string>* provided) const {
  1552. for (int i = 0; i < fields.size(); i++) {
  1553. const FieldDescriptor* field = fields[i];
  1554. if (IgnoreField(field)) {
  1555. continue;
  1556. }
  1557. std::string name = GetNamespace(options, field->file()) + "." +
  1558. JSObjectFieldName(options, field);
  1559. provided->insert(name);
  1560. }
  1561. }
  1562. void Generator::GenerateProvides(const GeneratorOptions& options,
  1563. io::Printer* printer,
  1564. std::set<std::string>* provided) const {
  1565. for (std::set<std::string>::iterator it = provided->begin();
  1566. it != provided->end(); ++it) {
  1567. if (options.import_style == GeneratorOptions::kImportClosure) {
  1568. printer->Print("goog.provide('$name$');\n", "name", *it);
  1569. } else {
  1570. // We aren't using Closure's import system, but we use goog.exportSymbol()
  1571. // to construct the expected tree of objects, eg.
  1572. //
  1573. // goog.exportSymbol('foo.bar.Baz', null, this);
  1574. //
  1575. // // Later generated code expects foo.bar = {} to exist:
  1576. // foo.bar.Baz = function() { /* ... */ }
  1577. // Do not use global scope in strict mode
  1578. if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
  1579. std::string namespaceObject = *it;
  1580. // Remove "proto." from the namespace object
  1581. GOOGLE_CHECK_EQ(0, namespaceObject.compare(0, 6, "proto."));
  1582. namespaceObject.erase(0, 6);
  1583. printer->Print("goog.exportSymbol('$name$', null, proto);\n", "name",
  1584. namespaceObject);
  1585. } else {
  1586. printer->Print("goog.exportSymbol('$name$', null, global);\n", "name",
  1587. *it);
  1588. }
  1589. }
  1590. }
  1591. }
  1592. void Generator::GenerateRequiresForSCC(const GeneratorOptions& options,
  1593. io::Printer* printer, const SCC* scc,
  1594. std::set<std::string>* provided) const {
  1595. std::set<std::string> required;
  1596. std::set<std::string> forwards;
  1597. bool have_message = false;
  1598. bool has_extension = false;
  1599. bool has_map = false;
  1600. for (auto desc : scc->descriptors) {
  1601. if (desc->containing_type() == nullptr) {
  1602. FindRequiresForMessage(options, desc, &required, &forwards,
  1603. &have_message);
  1604. has_extension = (has_extension || HasExtensions(desc));
  1605. has_map = (has_map || HasMap(options, desc));
  1606. }
  1607. }
  1608. GenerateRequiresImpl(options, printer, &required, &forwards, provided,
  1609. /* require_jspb = */ have_message,
  1610. /* require_extension = */ has_extension,
  1611. /* require_map = */ has_map);
  1612. }
  1613. void Generator::GenerateRequiresForLibrary(
  1614. const GeneratorOptions& options, io::Printer* printer,
  1615. const std::vector<const FileDescriptor*>& files,
  1616. std::set<std::string>* provided) const {
  1617. GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::kImportClosure);
  1618. // For Closure imports we need to import every message type individually.
  1619. std::set<std::string> required;
  1620. std::set<std::string> forwards;
  1621. bool have_extensions = false;
  1622. bool have_map = false;
  1623. bool have_message = false;
  1624. for (int i = 0; i < files.size(); i++) {
  1625. for (int j = 0; j < files[i]->message_type_count(); j++) {
  1626. const Descriptor* desc = files[i]->message_type(j);
  1627. if (!IgnoreMessage(desc)) {
  1628. FindRequiresForMessage(options, desc, &required, &forwards,
  1629. &have_message);
  1630. }
  1631. }
  1632. if (!have_extensions && HasExtensions(files[i])) {
  1633. have_extensions = true;
  1634. }
  1635. if (!have_map && FileHasMap(options, files[i])) {
  1636. have_map = true;
  1637. }
  1638. for (int j = 0; j < files[i]->extension_count(); j++) {
  1639. const FieldDescriptor* extension = files[i]->extension(j);
  1640. if (IgnoreField(extension)) {
  1641. continue;
  1642. }
  1643. if (extension->containing_type()->full_name() !=
  1644. "google.protobuf.bridge.MessageSet") {
  1645. required.insert(GetMessagePath(options, extension->containing_type()));
  1646. }
  1647. FindRequiresForField(options, extension, &required, &forwards);
  1648. have_extensions = true;
  1649. }
  1650. }
  1651. GenerateRequiresImpl(options, printer, &required, &forwards, provided,
  1652. /* require_jspb = */ have_message,
  1653. /* require_extension = */ have_extensions,
  1654. /* require_map = */ have_map);
  1655. }
  1656. void Generator::GenerateRequiresForExtensions(
  1657. const GeneratorOptions& options, io::Printer* printer,
  1658. const std::vector<const FieldDescriptor*>& fields,
  1659. std::set<std::string>* provided) const {
  1660. std::set<std::string> required;
  1661. std::set<std::string> forwards;
  1662. for (int i = 0; i < fields.size(); i++) {
  1663. const FieldDescriptor* field = fields[i];
  1664. if (IgnoreField(field)) {
  1665. continue;
  1666. }
  1667. FindRequiresForExtension(options, field, &required, &forwards);
  1668. }
  1669. GenerateRequiresImpl(options, printer, &required, &forwards, provided,
  1670. /* require_jspb = */ false,
  1671. /* require_extension = */ fields.size() > 0,
  1672. /* require_map = */ false);
  1673. }
  1674. void Generator::GenerateRequiresImpl(const GeneratorOptions& options,
  1675. io::Printer* printer,
  1676. std::set<std::string>* required,
  1677. std::set<std::string>* forwards,
  1678. std::set<std::string>* provided,
  1679. bool require_jspb, bool require_extension,
  1680. bool require_map) const {
  1681. if (require_jspb) {
  1682. required->insert("jspb.Message");
  1683. required->insert("jspb.BinaryReader");
  1684. required->insert("jspb.BinaryWriter");
  1685. }
  1686. if (require_extension) {
  1687. required->insert("jspb.ExtensionFieldBinaryInfo");
  1688. required->insert("jspb.ExtensionFieldInfo");
  1689. }
  1690. if (require_map) {
  1691. required->insert("jspb.Map");
  1692. }
  1693. std::set<std::string>::iterator it;
  1694. for (it = required->begin(); it != required->end(); ++it) {
  1695. if (provided->find(*it) != provided->end()) {
  1696. continue;
  1697. }
  1698. printer->Print("goog.require('$name$');\n", "name", *it);
  1699. }
  1700. printer->Print("\n");
  1701. for (it = forwards->begin(); it != forwards->end(); ++it) {
  1702. if (provided->find(*it) != provided->end()) {
  1703. continue;
  1704. }
  1705. printer->Print("goog.forwardDeclare('$name$');\n", "name", *it);
  1706. }
  1707. }
  1708. bool NamespaceOnly(const Descriptor* desc) { return false; }
  1709. void Generator::FindRequiresForMessage(const GeneratorOptions& options,
  1710. const Descriptor* desc,
  1711. std::set<std::string>* required,
  1712. std::set<std::string>* forwards,
  1713. bool* have_message) const {
  1714. if (!NamespaceOnly(desc)) {
  1715. *have_message = true;
  1716. for (int i = 0; i < desc->field_count(); i++) {
  1717. const FieldDescriptor* field = desc->field(i);
  1718. if (IgnoreField(field)) {
  1719. continue;
  1720. }
  1721. FindRequiresForField(options, field, required, forwards);
  1722. }
  1723. }
  1724. for (int i = 0; i < desc->extension_count(); i++) {
  1725. const FieldDescriptor* field = desc->extension(i);
  1726. if (IgnoreField(field)) {
  1727. continue;
  1728. }
  1729. FindRequiresForExtension(options, field, required, forwards);
  1730. }
  1731. for (int i = 0; i < desc->nested_type_count(); i++) {
  1732. FindRequiresForMessage(options, desc->nested_type(i), required, forwards,
  1733. have_message);
  1734. }
  1735. }
  1736. void Generator::FindRequiresForField(const GeneratorOptions& options,
  1737. const FieldDescriptor* field,
  1738. std::set<std::string>* required,
  1739. std::set<std::string>* forwards) const {
  1740. if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
  1741. // N.B.: file-level extensions with enum type do *not* create
  1742. // dependencies, as per original codegen.
  1743. !(field->is_extension() && field->extension_scope() == nullptr)) {
  1744. if (options.add_require_for_enums) {
  1745. required->insert(GetEnumPath(options, field->enum_type()));
  1746. } else {
  1747. forwards->insert(GetEnumPath(options, field->enum_type()));
  1748. }
  1749. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  1750. if (!IgnoreMessage(field->message_type())) {
  1751. required->insert(GetMessagePath(options, field->message_type()));
  1752. }
  1753. }
  1754. }
  1755. void Generator::FindRequiresForExtension(
  1756. const GeneratorOptions& options, const FieldDescriptor* field,
  1757. std::set<std::string>* required, std::set<std::string>* forwards) const {
  1758. if (field->containing_type()->full_name() !=
  1759. "google.protobuf.bridge.MessageSet") {
  1760. required->insert(GetMessagePath(options, field->containing_type()));
  1761. }
  1762. FindRequiresForField(options, field, required, forwards);
  1763. }
  1764. void Generator::GenerateTestOnly(const GeneratorOptions& options,
  1765. io::Printer* printer) const {
  1766. if (options.testonly) {
  1767. printer->Print("goog.setTestOnly();\n\n");
  1768. }
  1769. printer->Print("\n");
  1770. }
  1771. void Generator::GenerateClassesAndEnums(const GeneratorOptions& options,
  1772. io::Printer* printer,
  1773. const FileDescriptor* file) const {
  1774. for (int i = 0; i < file->message_type_count(); i++) {
  1775. GenerateClassConstructorAndDeclareExtensionFieldInfo(options, printer,
  1776. file->message_type(i));
  1777. }
  1778. for (int i = 0; i < file->message_type_count(); i++) {
  1779. GenerateClass(options, printer, file->message_type(i));
  1780. }
  1781. for (int i = 0; i < file->enum_type_count(); i++) {
  1782. GenerateEnum(options, printer, file->enum_type(i));
  1783. }
  1784. }
  1785. void Generator::GenerateClass(const GeneratorOptions& options,
  1786. io::Printer* printer,
  1787. const Descriptor* desc) const {
  1788. if (IgnoreMessage(desc)) {
  1789. return;
  1790. }
  1791. if (!NamespaceOnly(desc)) {
  1792. printer->Print("\n");
  1793. GenerateClassFieldInfo(options, printer, desc);
  1794. GenerateClassToObject(options, printer, desc);
  1795. // These must come *before* the extension-field info generation in
  1796. // GenerateClassRegistration so that references to the binary
  1797. // serialization/deserialization functions may be placed in the extension
  1798. // objects.
  1799. GenerateClassDeserializeBinary(options, printer, desc);
  1800. GenerateClassSerializeBinary(options, printer, desc);
  1801. }
  1802. // Recurse on nested types. These must come *before* the extension-field
  1803. // info generation in GenerateClassRegistration so that extensions that
  1804. // reference nested types proceed the definitions of the nested types.
  1805. for (int i = 0; i < desc->enum_type_count(); i++) {
  1806. GenerateEnum(options, printer, desc->enum_type(i));
  1807. }
  1808. for (int i = 0; i < desc->nested_type_count(); i++) {
  1809. GenerateClass(options, printer, desc->nested_type(i));
  1810. }
  1811. if (!NamespaceOnly(desc)) {
  1812. GenerateClassRegistration(options, printer, desc);
  1813. GenerateClassFields(options, printer, desc);
  1814. if (options.import_style != GeneratorOptions::kImportClosure) {
  1815. for (int i = 0; i < desc->extension_count(); i++) {
  1816. GenerateExtension(options, printer, desc->extension(i));
  1817. }
  1818. }
  1819. }
  1820. }
  1821. void Generator::GenerateClassConstructor(const GeneratorOptions& options,
  1822. io::Printer* printer,
  1823. const Descriptor* desc) const {
  1824. printer->Print(
  1825. "/**\n"
  1826. " * Generated by JsPbCodeGenerator.\n"
  1827. " * @param {Array=} opt_data Optional initial data array, typically "
  1828. "from a\n"
  1829. " * server response, or constructed directly in Javascript. The array "
  1830. "is used\n"
  1831. " * in place and becomes part of the constructed object. It is not "
  1832. "cloned.\n"
  1833. " * If no data is provided, the constructed object will be empty, but "
  1834. "still\n"
  1835. " * valid.\n"
  1836. " * @extends {jspb.Message}\n"
  1837. " * @constructor\n"
  1838. " */\n"
  1839. "$classprefix$$classname$ = function(opt_data) {\n",
  1840. "classprefix", GetMessagePathPrefix(options, desc), "classname",
  1841. desc->name());
  1842. printer->Annotate("classname", desc);
  1843. std::string message_id = GetMessageId(desc);
  1844. printer->Print(
  1845. " jspb.Message.initialize(this, opt_data, $messageId$, $pivot$, "
  1846. "$rptfields$, $oneoffields$);\n",
  1847. "messageId",
  1848. !message_id.empty() ? ("'" + message_id + "'")
  1849. : (IsResponse(desc) ? "''" : "0"),
  1850. "pivot", GetPivot(desc), "rptfields",
  1851. RepeatedFieldsArrayName(options, desc), "oneoffields",
  1852. OneofFieldsArrayName(options, desc));
  1853. printer->Print(
  1854. "};\n"
  1855. "goog.inherits($classname$, jspb.Message);\n"
  1856. "if (goog.DEBUG && !COMPILED) {\n"
  1857. // displayName overrides Function.prototype.displayName
  1858. // http://google3/javascript/externs/es3.js?l=511
  1859. " /**\n"
  1860. " * @public\n"
  1861. " * @override\n"
  1862. " */\n"
  1863. " $classname$.displayName = '$classname$';\n"
  1864. "}\n",
  1865. "classname", GetMessagePath(options, desc));
  1866. }
  1867. void Generator::GenerateClassConstructorAndDeclareExtensionFieldInfo(
  1868. const GeneratorOptions& options, io::Printer* printer,
  1869. const Descriptor* desc) const {
  1870. if (!NamespaceOnly(desc)) {
  1871. GenerateClassConstructor(options, printer, desc);
  1872. if (IsExtendable(desc) &&
  1873. desc->full_name() != "google.protobuf.bridge.MessageSet") {
  1874. GenerateClassExtensionFieldInfo(options, printer, desc);
  1875. }
  1876. }
  1877. for (int i = 0; i < desc->nested_type_count(); i++) {
  1878. if (!IgnoreMessage(desc->nested_type(i))) {
  1879. GenerateClassConstructorAndDeclareExtensionFieldInfo(
  1880. options, printer, desc->nested_type(i));
  1881. }
  1882. }
  1883. }
  1884. void Generator::GenerateClassFieldInfo(const GeneratorOptions& options,
  1885. io::Printer* printer,
  1886. const Descriptor* desc) const {
  1887. if (HasRepeatedFields(options, desc)) {
  1888. printer->Print(
  1889. "/**\n"
  1890. " * List of repeated fields within this message type.\n"
  1891. " * @private {!Array<number>}\n"
  1892. " * @const\n"
  1893. " */\n"
  1894. "$classname$$rptfieldarray$ = $rptfields$;\n"
  1895. "\n",
  1896. "classname", GetMessagePath(options, desc), "rptfieldarray",
  1897. kRepeatedFieldArrayName, "rptfields",
  1898. RepeatedFieldNumberList(options, desc));
  1899. }
  1900. if (HasOneofFields(desc)) {
  1901. printer->Print(
  1902. "/**\n"
  1903. " * Oneof group definitions for this message. Each group defines the "
  1904. "field\n"
  1905. " * numbers belonging to that group. When of these fields' value is "
  1906. "set, all\n"
  1907. " * other fields in the group are cleared. During deserialization, if "
  1908. "multiple\n"
  1909. " * fields are encountered for a group, only the last value seen will "
  1910. "be kept.\n"
  1911. " * @private {!Array<!Array<number>>}\n"
  1912. " * @const\n"
  1913. " */\n"
  1914. "$classname$$oneofgrouparray$ = $oneofgroups$;\n"
  1915. "\n",
  1916. "classname", GetMessagePath(options, desc), "oneofgrouparray",
  1917. kOneofGroupArrayName, "oneofgroups", OneofGroupList(desc));
  1918. for (int i = 0; i < desc->oneof_decl_count(); i++) {
  1919. if (IgnoreOneof(desc->oneof_decl(i))) {
  1920. continue;
  1921. }
  1922. GenerateOneofCaseDefinition(options, printer, desc->oneof_decl(i));
  1923. }
  1924. }
  1925. }
  1926. void Generator::GenerateClassXid(const GeneratorOptions& options,
  1927. io::Printer* printer,
  1928. const Descriptor* desc) const {
  1929. printer->Print(
  1930. "\n"
  1931. "\n"
  1932. "$class$.prototype.messageXid = xid('$class$');\n",
  1933. "class", GetMessagePath(options, desc));
  1934. }
  1935. void Generator::GenerateOneofCaseDefinition(
  1936. const GeneratorOptions& options, io::Printer* printer,
  1937. const OneofDescriptor* oneof) const {
  1938. printer->Print(
  1939. "/**\n"
  1940. " * @enum {number}\n"
  1941. " */\n"
  1942. "$classname$.$oneof$Case = {\n"
  1943. " $upcase$_NOT_SET: 0",
  1944. "classname", GetMessagePath(options, oneof->containing_type()), "oneof",
  1945. JSOneofName(oneof), "upcase", ToEnumCase(oneof->name()));
  1946. for (int i = 0; i < oneof->field_count(); i++) {
  1947. if (IgnoreField(oneof->field(i))) {
  1948. continue;
  1949. }
  1950. printer->Print(
  1951. ",\n"
  1952. " $upcase$: $number$",
  1953. "upcase", ToEnumCase(oneof->field(i)->name()), "number",
  1954. JSFieldIndex(oneof->field(i)));
  1955. printer->Annotate("upcase", oneof->field(i));
  1956. }
  1957. printer->Print(
  1958. "\n"
  1959. "};\n"
  1960. "\n"
  1961. "/**\n"
  1962. " * @return {$class$.$oneof$Case}\n"
  1963. " */\n"
  1964. "$class$.prototype.get$oneof$Case = function() {\n"
  1965. " return /** @type {$class$.$oneof$Case} */(jspb.Message."
  1966. "computeOneofCase(this, $class$.oneofGroups_[$oneofindex$]));\n"
  1967. "};\n"
  1968. "\n",
  1969. "class", GetMessagePath(options, oneof->containing_type()), "oneof",
  1970. JSOneofName(oneof), "oneofindex", JSOneofIndex(oneof));
  1971. }
  1972. void Generator::GenerateClassToObject(const GeneratorOptions& options,
  1973. io::Printer* printer,
  1974. const Descriptor* desc) const {
  1975. printer->Print(
  1976. "\n"
  1977. "\n"
  1978. "if (jspb.Message.GENERATE_TO_OBJECT) {\n"
  1979. "/**\n"
  1980. " * Creates an object representation of this proto.\n"
  1981. " * Field names that are reserved in JavaScript and will be renamed to "
  1982. "pb_name.\n"
  1983. " * Optional fields that are not set will be set to undefined.\n"
  1984. " * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.\n"
  1985. " * For the list of reserved names please see:\n"
  1986. " * net/proto2/compiler/js/internal/generator.cc#kKeyword.\n"
  1987. " * @param {boolean=} opt_includeInstance Deprecated. whether to include "
  1988. "the\n"
  1989. " * JSPB instance for transitional soy proto support:\n"
  1990. " * http://goto/soy-param-migration\n"
  1991. " * @return {!Object}\n"
  1992. " */\n"
  1993. "$classname$.prototype.toObject = function(opt_includeInstance) {\n"
  1994. " return $classname$.toObject(opt_includeInstance, this);\n"
  1995. "};\n"
  1996. "\n"
  1997. "\n"
  1998. "/**\n"
  1999. " * Static version of the {@see toObject} method.\n"
  2000. " * @param {boolean|undefined} includeInstance Deprecated. Whether to "
  2001. "include\n"
  2002. " * the JSPB instance for transitional soy proto support:\n"
  2003. " * http://goto/soy-param-migration\n"
  2004. " * @param {!$classname$} msg The msg instance to transform.\n"
  2005. " * @return {!Object}\n"
  2006. " * @suppress {unusedLocalVariables} f is only used for nested messages\n"
  2007. " */\n"
  2008. "$classname$.toObject = function(includeInstance, msg) {\n"
  2009. " var f, obj = {",
  2010. "classname", GetMessagePath(options, desc));
  2011. bool first = true;
  2012. for (int i = 0; i < desc->field_count(); i++) {
  2013. const FieldDescriptor* field = desc->field(i);
  2014. if (IgnoreField(field)) {
  2015. continue;
  2016. }
  2017. if (!first) {
  2018. printer->Print(",\n ");
  2019. } else {
  2020. printer->Print("\n ");
  2021. first = false;
  2022. }
  2023. GenerateClassFieldToObject(options, printer, field);
  2024. }
  2025. if (!first) {
  2026. printer->Print("\n };\n\n");
  2027. } else {
  2028. printer->Print("\n\n };\n\n");
  2029. }
  2030. if (IsExtendable(desc)) {
  2031. printer->Print(
  2032. " jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), "
  2033. "obj,\n"
  2034. " $extObject$, $class$.prototype.getExtension,\n"
  2035. " includeInstance);\n",
  2036. "extObject", JSExtensionsObjectName(options, desc->file(), desc),
  2037. "class", GetMessagePath(options, desc));
  2038. }
  2039. printer->Print(
  2040. " if (includeInstance) {\n"
  2041. " obj.$$jspbMessageInstance = msg;\n"
  2042. " }\n"
  2043. " return obj;\n"
  2044. "};\n"
  2045. "}\n"
  2046. "\n"
  2047. "\n",
  2048. "classname", GetMessagePath(options, desc));
  2049. }
  2050. void Generator::GenerateFieldValueExpression(io::Printer* printer,
  2051. const char* obj_reference,
  2052. const FieldDescriptor* field,
  2053. bool use_default) const {
  2054. const bool is_float_or_double =
  2055. field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
  2056. field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE;
  2057. const bool is_boolean = field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL;
  2058. const std::string with_default = use_default ? "WithDefault" : "";
  2059. const std::string default_arg =
  2060. use_default ? StrCat(", ", JSFieldDefault(field)) : "";
  2061. const std::string cardinality = field->is_repeated() ? "Repeated" : "";
  2062. std::string type = "";
  2063. if (is_float_or_double) {
  2064. type = "FloatingPoint";
  2065. }
  2066. if (is_boolean) {
  2067. type = "Boolean";
  2068. }
  2069. // Prints the appropriate function, among:
  2070. // - getField
  2071. // - getBooleanField
  2072. // - getFloatingPointField => Replaced by getOptionalFloatingPointField to
  2073. // preserve backward compatibility.
  2074. // - getFieldWithDefault
  2075. // - getBooleanFieldWithDefault
  2076. // - getFloatingPointFieldWithDefault
  2077. // - getRepeatedField
  2078. // - getRepeatedBooleanField
  2079. // - getRepeatedFloatingPointField
  2080. if (is_float_or_double && !field->is_repeated() && !use_default) {
  2081. printer->Print(
  2082. "jspb.Message.getOptionalFloatingPointField($obj$, "
  2083. "$index$$default$)",
  2084. "obj", obj_reference, "index", JSFieldIndex(field), "default",
  2085. default_arg);
  2086. } else {
  2087. printer->Print(
  2088. "jspb.Message.get$cardinality$$type$Field$with_default$($obj$, "
  2089. "$index$$default$)",
  2090. "cardinality", cardinality, "type", type, "with_default", with_default,
  2091. "obj", obj_reference, "index", JSFieldIndex(field), "default",
  2092. default_arg);
  2093. }
  2094. }
  2095. void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
  2096. io::Printer* printer,
  2097. const FieldDescriptor* field) const {
  2098. printer->Print("$fieldname$: ", "fieldname",
  2099. JSObjectFieldName(options, field));
  2100. if (field->is_map()) {
  2101. const FieldDescriptor* value_field = MapFieldValue(field);
  2102. // If the map values are of a message type, we must provide their static
  2103. // toObject() method; otherwise we pass undefined for that argument.
  2104. std::string value_to_object;
  2105. if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  2106. value_to_object =
  2107. GetMessagePath(options, value_field->message_type()) + ".toObject";
  2108. } else {
  2109. value_to_object = "undefined";
  2110. }
  2111. printer->Print(
  2112. "(f = msg.get$name$()) ? f.toObject(includeInstance, $valuetoobject$) "
  2113. ": []",
  2114. "name", JSGetterName(options, field), "valuetoobject", value_to_object);
  2115. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  2116. // Message field.
  2117. if (field->is_repeated()) {
  2118. {
  2119. printer->Print(
  2120. "jspb.Message.toObjectList(msg.get$getter$(),\n"
  2121. " $type$.toObject, includeInstance)",
  2122. "getter", JSGetterName(options, field), "type",
  2123. SubmessageTypeRef(options, field));
  2124. }
  2125. } else {
  2126. printer->Print(
  2127. "(f = msg.get$getter$()) && "
  2128. "$type$.toObject(includeInstance, f)",
  2129. "getter", JSGetterName(options, field), "type",
  2130. SubmessageTypeRef(options, field));
  2131. }
  2132. } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
  2133. // For bytes fields we want to always return the B64 data.
  2134. printer->Print("msg.get$getter$()", "getter",
  2135. JSGetterName(options, field, BYTES_B64));
  2136. } else {
  2137. bool use_default = field->has_default_value();
  2138. if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
  2139. // Repeated fields get initialized to their default in the constructor
  2140. // (why?), so we emit a plain getField() call for them.
  2141. !field->is_repeated()) {
  2142. // Proto3 puts all defaults (including implicit defaults) in toObject().
  2143. // But for proto2 we leave the existing semantics unchanged: unset fields
  2144. // without default are unset.
  2145. use_default = true;
  2146. }
  2147. // We don't implement this by calling the accessors, because the semantics
  2148. // of the accessors are changing independently of the toObject() semantics.
  2149. // We are migrating the accessors to return defaults instead of null, but
  2150. // it may take longer to migrate toObject (or we might not want to do it at
  2151. // all). So we want to generate independent code.
  2152. // The accessor for unset optional values without default should return
  2153. // null. Those are converted to undefined in the generated object.
  2154. if (!use_default) {
  2155. printer->Print("(f = ");
  2156. }
  2157. GenerateFieldValueExpression(printer, "msg", field, use_default);
  2158. if (!use_default) {
  2159. printer->Print(") == null ? undefined : f");
  2160. }
  2161. }
  2162. }
  2163. void Generator::GenerateObjectTypedef(const GeneratorOptions& options,
  2164. io::Printer* printer,
  2165. const Descriptor* desc) const {
  2166. // TODO(b/122687752): Consider renaming nested messages called ObjectFormat
  2167. // to prevent collisions.
  2168. const std::string type_name = GetMessagePath(options, desc) + ".ObjectFormat";
  2169. printer->Print(
  2170. "/**\n"
  2171. " * The raw object form of $messageName$ as accepted by the `fromObject` "
  2172. "method.\n"
  2173. " * @record\n"
  2174. " */\n"
  2175. "$typeName$ = function() {\n",
  2176. "messageName", desc->name(), "typeName", type_name);
  2177. for (int i = 0; i < desc->field_count(); i++) {
  2178. if (i > 0) {
  2179. printer->Print("\n");
  2180. }
  2181. printer->Print(
  2182. " /** @type {$fieldType$|undefined} */\n"
  2183. " this.$fieldName$;\n",
  2184. "fieldName", JSObjectFieldName(options, desc->field(i)),
  2185. // TODO(b/121097361): Add type checking for field values.
  2186. "fieldType", "?");
  2187. }
  2188. printer->Print("};\n\n");
  2189. }
  2190. void Generator::GenerateClassFromObject(const GeneratorOptions& options,
  2191. io::Printer* printer,
  2192. const Descriptor* desc) const {
  2193. printer->Print("if (jspb.Message.GENERATE_FROM_OBJECT) {\n\n");
  2194. GenerateObjectTypedef(options, printer, desc);
  2195. printer->Print(
  2196. "/**\n"
  2197. " * Loads data from an object into a new instance of this proto.\n"
  2198. " * @param {!$classname$.ObjectFormat} obj\n"
  2199. " * The object representation of this proto to load the data from.\n"
  2200. " * @return {!$classname$}\n"
  2201. " */\n"
  2202. "$classname$.fromObject = function(obj) {\n"
  2203. " var msg = new $classname$();\n",
  2204. "classname", GetMessagePath(options, desc));
  2205. for (int i = 0; i < desc->field_count(); i++) {
  2206. const FieldDescriptor* field = desc->field(i);
  2207. if (!IgnoreField(field)) {
  2208. GenerateClassFieldFromObject(options, printer, field);
  2209. }
  2210. }
  2211. printer->Print(
  2212. " return msg;\n"
  2213. "};\n"
  2214. "}\n\n");
  2215. }
  2216. void Generator::GenerateClassFieldFromObject(
  2217. const GeneratorOptions& options, io::Printer* printer,
  2218. const FieldDescriptor* field) const {
  2219. if (field->is_map()) {
  2220. const FieldDescriptor* value_field = MapFieldValue(field);
  2221. if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
  2222. // Since the map values are of message type, we have to do some extra work
  2223. // to recursively call fromObject() on them before setting the map field.
  2224. printer->Print(
  2225. " obj.$name$ && jspb.Message.setWrapperField(\n"
  2226. " msg, $index$, jspb.Map.fromObject(obj.$name$, $fieldclass$, "
  2227. "$fieldclass$.fromObject));\n",
  2228. "name", JSObjectFieldName(options, field), "index",
  2229. JSFieldIndex(field), "fieldclass",
  2230. GetMessagePath(options, value_field->message_type()));
  2231. } else {
  2232. // `msg` is a newly-constructed message object that has not yet built any
  2233. // map containers wrapping underlying arrays, so we can simply directly
  2234. // set the array here without fear of a stale wrapper.
  2235. printer->Print(
  2236. " obj.$name$ && "
  2237. "jspb.Message.setField(msg, $index$, obj.$name$);\n",
  2238. "name", JSObjectFieldName(options, field), "index",
  2239. JSFieldIndex(field));
  2240. }
  2241. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  2242. // Message field (singular or repeated)
  2243. if (field->is_repeated()) {
  2244. {
  2245. printer->Print(
  2246. " obj.$name$ && "
  2247. "jspb.Message.setRepeatedWrapperField(\n"
  2248. " msg, $index$, obj.$name$.map(\n"
  2249. " $fieldclass$.fromObject));\n",
  2250. "name", JSObjectFieldName(options, field), "index",
  2251. JSFieldIndex(field), "fieldclass",
  2252. SubmessageTypeRef(options, field));
  2253. }
  2254. } else {
  2255. printer->Print(
  2256. " obj.$name$ && jspb.Message.setWrapperField(\n"
  2257. " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
  2258. "name", JSObjectFieldName(options, field), "index",
  2259. JSFieldIndex(field), "fieldclass", SubmessageTypeRef(options, field));
  2260. }
  2261. } else {
  2262. // Simple (primitive) field.
  2263. printer->Print(
  2264. " obj.$name$ != null && jspb.Message.setField(msg, $index$, "
  2265. "obj.$name$);\n",
  2266. "name", JSObjectFieldName(options, field), "index",
  2267. JSFieldIndex(field));
  2268. }
  2269. }
  2270. void Generator::GenerateClassRegistration(const GeneratorOptions& options,
  2271. io::Printer* printer,
  2272. const Descriptor* desc) const {
  2273. // Register any extensions defined inside this message type.
  2274. for (int i = 0; i < desc->extension_count(); i++) {
  2275. const FieldDescriptor* extension = desc->extension(i);
  2276. if (ShouldGenerateExtension(extension)) {
  2277. GenerateExtension(options, printer, extension);
  2278. }
  2279. }
  2280. }
  2281. void Generator::GenerateClassFields(const GeneratorOptions& options,
  2282. io::Printer* printer,
  2283. const Descriptor* desc) const {
  2284. for (int i = 0; i < desc->field_count(); i++) {
  2285. if (!IgnoreField(desc->field(i))) {
  2286. GenerateClassField(options, printer, desc->field(i));
  2287. }
  2288. }
  2289. }
  2290. void GenerateBytesWrapper(const GeneratorOptions& options, io::Printer* printer,
  2291. const FieldDescriptor* field, BytesMode bytes_mode) {
  2292. std::string type =
  2293. JSFieldTypeAnnotation(options, field,
  2294. /* is_setter_argument = */ false,
  2295. /* force_present = */ false,
  2296. /* singular_if_not_packed = */ false, bytes_mode);
  2297. printer->Print(
  2298. "/**\n"
  2299. " * $fielddef$\n"
  2300. "$comment$"
  2301. " * This is a type-conversion wrapper around `get$defname$()`\n"
  2302. " * @return {$type$}\n"
  2303. " */\n"
  2304. "$class$.prototype.get$name$ = function() {\n"
  2305. " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n"
  2306. " this.get$defname$()));\n"
  2307. "};\n"
  2308. "\n"
  2309. "\n",
  2310. "fielddef", FieldDefinition(options, field), "comment",
  2311. FieldComments(field, bytes_mode), "type", type, "class",
  2312. GetMessagePath(options, field->containing_type()), "name",
  2313. JSGetterName(options, field, bytes_mode), "list",
  2314. field->is_repeated() ? "List" : "", "suffix",
  2315. JSByteGetterSuffix(bytes_mode), "defname",
  2316. JSGetterName(options, field, BYTES_DEFAULT));
  2317. }
  2318. void Generator::GenerateClassField(const GeneratorOptions& options,
  2319. io::Printer* printer,
  2320. const FieldDescriptor* field) const {
  2321. if (field->is_map()) {
  2322. const FieldDescriptor* key_field = MapFieldKey(field);
  2323. const FieldDescriptor* value_field = MapFieldValue(field);
  2324. // Map field: special handling to instantiate the map object on demand.
  2325. std::string key_type =
  2326. JSFieldTypeAnnotation(options, key_field,
  2327. /* is_setter_argument = */ false,
  2328. /* force_present = */ true,
  2329. /* singular_if_not_packed = */ false);
  2330. std::string value_type =
  2331. JSFieldTypeAnnotation(options, value_field,
  2332. /* is_setter_argument = */ false,
  2333. /* force_present = */ true,
  2334. /* singular_if_not_packed = */ false);
  2335. printer->Print(
  2336. "/**\n"
  2337. " * $fielddef$\n"
  2338. " * @param {boolean=} opt_noLazyCreate Do not create the map if\n"
  2339. " * empty, instead returning `undefined`\n"
  2340. " * @return {!jspb.Map<$keytype$,$valuetype$>}\n"
  2341. " */\n",
  2342. "fielddef", FieldDefinition(options, field), "keytype", key_type,
  2343. "valuetype", value_type);
  2344. printer->Print(
  2345. "$class$.prototype.$gettername$ = function(opt_noLazyCreate) {\n"
  2346. " return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n",
  2347. "class", GetMessagePath(options, field->containing_type()),
  2348. "gettername", "get" + JSGetterName(options, field), "keytype", key_type,
  2349. "valuetype", value_type);
  2350. printer->Annotate("gettername", field);
  2351. printer->Print(
  2352. " jspb.Message.getMapField(this, $index$, opt_noLazyCreate",
  2353. "index", JSFieldIndex(field));
  2354. if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
  2355. printer->Print(
  2356. ",\n"
  2357. " $messageType$",
  2358. "messageType", GetMessagePath(options, value_field->message_type()));
  2359. } else {
  2360. printer->Print(
  2361. ",\n"
  2362. " null");
  2363. }
  2364. printer->Print("));\n");
  2365. printer->Print(
  2366. "};\n"
  2367. "\n"
  2368. "\n");
  2369. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  2370. // Message field: special handling in order to wrap the underlying data
  2371. // array with a message object.
  2372. printer->Print(
  2373. "/**\n"
  2374. " * $fielddef$\n"
  2375. "$comment$"
  2376. " * @return {$type$}\n"
  2377. " */\n",
  2378. "fielddef", FieldDefinition(options, field), "comment",
  2379. FieldComments(field, BYTES_DEFAULT), "type",
  2380. JSFieldTypeAnnotation(options, field,
  2381. /* is_setter_argument = */ false,
  2382. /* force_present = */ false,
  2383. /* singular_if_not_packed = */ false));
  2384. printer->Print(
  2385. "$class$.prototype.$gettername$ = function() {\n"
  2386. " return /** @type{$type$} */ (\n"
  2387. " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, "
  2388. "$index$$required$));\n"
  2389. "};\n"
  2390. "\n"
  2391. "\n",
  2392. "class", GetMessagePath(options, field->containing_type()),
  2393. "gettername", "get" + JSGetterName(options, field), "type",
  2394. JSFieldTypeAnnotation(options, field,
  2395. /* is_setter_argument = */ false,
  2396. /* force_present = */ false,
  2397. /* singular_if_not_packed = */ false),
  2398. "rpt", (field->is_repeated() ? "Repeated" : ""), "index",
  2399. JSFieldIndex(field), "wrapperclass", SubmessageTypeRef(options, field),
  2400. "required",
  2401. (field->label() == FieldDescriptor::LABEL_REQUIRED ? ", 1" : ""));
  2402. printer->Annotate("gettername", field);
  2403. printer->Print(
  2404. "/**\n"
  2405. " * @param {$optionaltype$} value\n"
  2406. " * @return {!$class$} returns this\n"
  2407. "*/\n"
  2408. "$class$.prototype.$settername$ = function(value) {\n"
  2409. " return jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
  2410. "optionaltype",
  2411. JSFieldTypeAnnotation(options, field,
  2412. /* is_setter_argument = */ true,
  2413. /* force_present = */ false,
  2414. /* singular_if_not_packed = */ false),
  2415. "class", GetMessagePath(options, field->containing_type()),
  2416. "settername", "set" + JSGetterName(options, field), "oneoftag",
  2417. (InRealOneof(field) ? "Oneof" : ""), "repeatedtag",
  2418. (field->is_repeated() ? "Repeated" : ""));
  2419. printer->Annotate("settername", field);
  2420. printer->Print(
  2421. "this, $index$$oneofgroup$, value);\n"
  2422. "};\n"
  2423. "\n"
  2424. "\n",
  2425. "index", JSFieldIndex(field), "oneofgroup",
  2426. (InRealOneof(field) ? (", " + JSOneofArray(options, field)) : ""));
  2427. if (field->is_repeated()) {
  2428. GenerateRepeatedMessageHelperMethods(options, printer, field);
  2429. }
  2430. } else {
  2431. bool untyped = false;
  2432. // Simple (primitive) field, either singular or repeated.
  2433. // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type;
  2434. // at this point we "lie" to non-binary users and tell the return
  2435. // type is always base64 string, pending a LSC to migrate to typed getters.
  2436. BytesMode bytes_mode =
  2437. field->type() == FieldDescriptor::TYPE_BYTES && !options.binary
  2438. ? BYTES_B64
  2439. : BYTES_DEFAULT;
  2440. std::string typed_annotation =
  2441. JSFieldTypeAnnotation(options, field,
  2442. /* is_setter_argument = */ false,
  2443. /* force_present = */ false,
  2444. /* singular_if_not_packed = */ false,
  2445. /* bytes_mode = */ bytes_mode);
  2446. if (untyped) {
  2447. printer->Print(
  2448. "/**\n"
  2449. " * @return {?} Raw field, untyped.\n"
  2450. " */\n");
  2451. } else {
  2452. printer->Print(
  2453. "/**\n"
  2454. " * $fielddef$\n"
  2455. "$comment$"
  2456. " * @return {$type$}\n"
  2457. " */\n",
  2458. "fielddef", FieldDefinition(options, field), "comment",
  2459. FieldComments(field, bytes_mode), "type", typed_annotation);
  2460. }
  2461. printer->Print("$class$.prototype.$gettername$ = function() {\n", "class",
  2462. GetMessagePath(options, field->containing_type()),
  2463. "gettername", "get" + JSGetterName(options, field));
  2464. printer->Annotate("gettername", field);
  2465. if (untyped) {
  2466. printer->Print(" return ");
  2467. } else {
  2468. printer->Print(" return /** @type {$type$} */ (", "type",
  2469. typed_annotation);
  2470. }
  2471. bool use_default = !ReturnsNullWhenUnset(options, field);
  2472. // Raw fields with no default set should just return undefined.
  2473. if (untyped && !field->has_default_value()) {
  2474. use_default = false;
  2475. }
  2476. // Repeated fields get initialized to their default in the constructor
  2477. // (why?), so we emit a plain getField() call for them.
  2478. if (field->is_repeated()) {
  2479. use_default = false;
  2480. }
  2481. GenerateFieldValueExpression(printer, "this", field, use_default);
  2482. if (untyped) {
  2483. printer->Print(
  2484. ";\n"
  2485. "};\n"
  2486. "\n"
  2487. "\n");
  2488. } else {
  2489. printer->Print(
  2490. ");\n"
  2491. "};\n"
  2492. "\n"
  2493. "\n");
  2494. }
  2495. if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) {
  2496. GenerateBytesWrapper(options, printer, field, BYTES_B64);
  2497. GenerateBytesWrapper(options, printer, field, BYTES_U8);
  2498. }
  2499. printer->Print(
  2500. "/**\n"
  2501. " * @param {$optionaltype$} value\n"
  2502. " * @return {!$class$} returns this\n"
  2503. " */\n",
  2504. "class", GetMessagePath(options, field->containing_type()),
  2505. "optionaltype",
  2506. untyped ? "*"
  2507. : JSFieldTypeAnnotation(options, field,
  2508. /* is_setter_argument = */ true,
  2509. /* force_present = */ false,
  2510. /* singular_if_not_packed = */ false));
  2511. if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
  2512. !field->is_repeated() && !field->is_map() &&
  2513. !HasFieldPresence(options, field)) {
  2514. // Proto3 non-repeated and non-map fields without presence use the
  2515. // setProto3*Field function.
  2516. printer->Print(
  2517. "$class$.prototype.$settername$ = function(value) {\n"
  2518. " return jspb.Message.setProto3$typetag$Field(this, $index$, "
  2519. "value);"
  2520. "\n"
  2521. "};\n"
  2522. "\n"
  2523. "\n",
  2524. "class", GetMessagePath(options, field->containing_type()),
  2525. "settername", "set" + JSGetterName(options, field), "typetag",
  2526. JSTypeTag(field), "index", JSFieldIndex(field));
  2527. printer->Annotate("settername", field);
  2528. } else {
  2529. // Otherwise, use the regular setField function.
  2530. printer->Print(
  2531. "$class$.prototype.$settername$ = function(value) {\n"
  2532. " return jspb.Message.set$oneoftag$Field(this, $index$",
  2533. "class", GetMessagePath(options, field->containing_type()),
  2534. "settername", "set" + JSGetterName(options, field), "oneoftag",
  2535. (InRealOneof(field) ? "Oneof" : ""), "index", JSFieldIndex(field));
  2536. printer->Annotate("settername", field);
  2537. printer->Print(
  2538. "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);\n"
  2539. "};\n"
  2540. "\n"
  2541. "\n",
  2542. "type",
  2543. untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "",
  2544. "typeclose", untyped ? ")" : "", "oneofgroup",
  2545. (InRealOneof(field) ? (", " + JSOneofArray(options, field)) : ""),
  2546. "rptvalueinit", (field->is_repeated() ? " || []" : ""));
  2547. }
  2548. if (untyped) {
  2549. printer->Print(
  2550. "/**\n"
  2551. " * Clears the value.\n"
  2552. " * @return {!$class$} returns this\n"
  2553. " */\n",
  2554. "class", GetMessagePath(options, field->containing_type()));
  2555. }
  2556. if (field->is_repeated()) {
  2557. GenerateRepeatedPrimitiveHelperMethods(options, printer, field, untyped);
  2558. }
  2559. }
  2560. // Generate clearFoo() method for map fields, repeated fields, and other
  2561. // fields with presence.
  2562. if (field->is_map()) {
  2563. // clang-format off
  2564. printer->Print(
  2565. "/**\n"
  2566. " * Clears values from the map. The map will be non-null.\n"
  2567. " * @return {!$class$} returns this\n"
  2568. " */\n"
  2569. "$class$.prototype.$clearername$ = function() {\n"
  2570. " this.$gettername$().clear();\n"
  2571. " return this;"
  2572. "};\n"
  2573. "\n"
  2574. "\n",
  2575. "class", GetMessagePath(options, field->containing_type()),
  2576. "clearername", "clear" + JSGetterName(options, field),
  2577. "gettername", "get" + JSGetterName(options, field));
  2578. // clang-format on
  2579. printer->Annotate("clearername", field);
  2580. } else if (field->is_repeated() ||
  2581. (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
  2582. !field->is_required())) {
  2583. // Fields where we can delegate to the regular setter.
  2584. // clang-format off
  2585. printer->Print(
  2586. "/**\n"
  2587. " * $jsdoc$\n"
  2588. " * @return {!$class$} returns this\n"
  2589. " */\n"
  2590. "$class$.prototype.$clearername$ = function() {\n"
  2591. " return this.$settername$($clearedvalue$);\n"
  2592. "};\n"
  2593. "\n"
  2594. "\n",
  2595. "jsdoc", field->is_repeated()
  2596. ? "Clears the list making it empty but non-null."
  2597. : "Clears the message field making it undefined.",
  2598. "class", GetMessagePath(options, field->containing_type()),
  2599. "clearername", "clear" + JSGetterName(options, field),
  2600. "settername", "set" + JSGetterName(options, field),
  2601. "clearedvalue", (field->is_repeated() ? "[]" : "undefined"));
  2602. // clang-format on
  2603. printer->Annotate("clearername", field);
  2604. } else if (HasFieldPresence(options, field)) {
  2605. // Fields where we can't delegate to the regular setter because it doesn't
  2606. // accept "undefined" as an argument.
  2607. // clang-format off
  2608. printer->Print(
  2609. "/**\n"
  2610. " * Clears the field making it undefined.\n"
  2611. " * @return {!$class$} returns this\n"
  2612. " */\n"
  2613. "$class$.prototype.$clearername$ = function() {\n"
  2614. " return jspb.Message.set$maybeoneof$Field(this, "
  2615. "$index$$maybeoneofgroup$, ",
  2616. "class", GetMessagePath(options, field->containing_type()),
  2617. "clearername", "clear" + JSGetterName(options, field),
  2618. "maybeoneof", (InRealOneof(field) ? "Oneof" : ""),
  2619. "maybeoneofgroup", (InRealOneof(field)
  2620. ? (", " + JSOneofArray(options, field))
  2621. : ""),
  2622. "index", JSFieldIndex(field));
  2623. // clang-format on
  2624. printer->Annotate("clearername", field);
  2625. printer->Print(
  2626. "$clearedvalue$);\n"
  2627. "};\n"
  2628. "\n"
  2629. "\n",
  2630. "clearedvalue", (field->is_repeated() ? "[]" : "undefined"));
  2631. }
  2632. if (HasFieldPresence(options, field)) {
  2633. printer->Print(
  2634. "/**\n"
  2635. " * Returns whether this field is set.\n"
  2636. " * @return {boolean}\n"
  2637. " */\n"
  2638. "$class$.prototype.$hasername$ = function() {\n"
  2639. " return jspb.Message.getField(this, $index$) != null;\n"
  2640. "};\n"
  2641. "\n"
  2642. "\n",
  2643. "class", GetMessagePath(options, field->containing_type()), "hasername",
  2644. "has" + JSGetterName(options, field), "index", JSFieldIndex(field));
  2645. printer->Annotate("hasername", field);
  2646. }
  2647. }
  2648. void Generator::GenerateRepeatedPrimitiveHelperMethods(
  2649. const GeneratorOptions& options, io::Printer* printer,
  2650. const FieldDescriptor* field, bool untyped) const {
  2651. // clang-format off
  2652. printer->Print(
  2653. "/**\n"
  2654. " * @param {$optionaltype$} value\n"
  2655. " * @param {number=} opt_index\n"
  2656. " * @return {!$class$} returns this\n"
  2657. " */\n"
  2658. "$class$.prototype.$addername$ = function(value, opt_index) {\n"
  2659. " return jspb.Message.addToRepeatedField(this, "
  2660. "$index$",
  2661. "class", GetMessagePath(options, field->containing_type()), "addername",
  2662. "add" + JSGetterName(options, field, BYTES_DEFAULT,
  2663. /* drop_list = */ true),
  2664. "optionaltype",
  2665. JSFieldTypeAnnotation(
  2666. options, field,
  2667. /* is_setter_argument = */ false,
  2668. /* force_present = */ true,
  2669. /* singular_if_not_packed = */ false,
  2670. BYTES_DEFAULT,
  2671. /* force_singular = */ true),
  2672. "index", JSFieldIndex(field));
  2673. printer->Annotate("addername", field);
  2674. printer->Print(
  2675. "$oneofgroup$, $type$value$rptvalueinit$$typeclose$, "
  2676. "opt_index);\n"
  2677. "};\n"
  2678. "\n"
  2679. "\n",
  2680. "type", untyped ? "/** @type{string|number|boolean|!Uint8Array} */(" : "",
  2681. "typeclose", untyped ? ")" : "", "oneofgroup",
  2682. (InRealOneof(field) ? (", " + JSOneofArray(options, field)) : ""),
  2683. "rptvalueinit", "");
  2684. // clang-format on
  2685. }
  2686. void Generator::GenerateRepeatedMessageHelperMethods(
  2687. const GeneratorOptions& options, io::Printer* printer,
  2688. const FieldDescriptor* field) const {
  2689. printer->Print(
  2690. "/**\n"
  2691. " * @param {!$optionaltype$=} opt_value\n"
  2692. " * @param {number=} opt_index\n"
  2693. " * @return {!$optionaltype$}\n"
  2694. " */\n"
  2695. "$class$.prototype.$addername$ = function(opt_value, opt_index) {\n"
  2696. " return jspb.Message.addTo$repeatedtag$WrapperField(",
  2697. "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "class",
  2698. GetMessagePath(options, field->containing_type()), "addername",
  2699. "add" + JSGetterName(options, field, BYTES_DEFAULT,
  2700. /* drop_list = */ true),
  2701. "repeatedtag", (field->is_repeated() ? "Repeated" : ""));
  2702. printer->Annotate("addername", field);
  2703. printer->Print(
  2704. "this, $index$$oneofgroup$, opt_value, $ctor$, opt_index);\n"
  2705. "};\n"
  2706. "\n"
  2707. "\n",
  2708. "index", JSFieldIndex(field), "oneofgroup",
  2709. (InRealOneof(field) ? (", " + JSOneofArray(options, field)) : ""), "ctor",
  2710. GetMessagePath(options, field->message_type()));
  2711. }
  2712. void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
  2713. io::Printer* printer,
  2714. const Descriptor* desc) const {
  2715. if (IsExtendable(desc)) {
  2716. printer->Print(
  2717. "\n"
  2718. "/**\n"
  2719. " * The extensions registered with this message class. This is a "
  2720. "map of\n"
  2721. " * extension field number to fieldInfo object.\n"
  2722. " *\n"
  2723. " * For example:\n"
  2724. " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, "
  2725. "ctor: proto.example.MyMessage} }\n"
  2726. " *\n"
  2727. " * fieldName contains the JsCompiler renamed field name property "
  2728. "so that it\n"
  2729. " * works in OPTIMIZED mode.\n"
  2730. " *\n"
  2731. " * @type {!Object<number, jspb.ExtensionFieldInfo>}\n"
  2732. " */\n"
  2733. "$class$.extensions = {};\n"
  2734. "\n",
  2735. "class", GetMessagePath(options, desc));
  2736. printer->Print(
  2737. "\n"
  2738. "/**\n"
  2739. " * The extensions registered with this message class. This is a "
  2740. "map of\n"
  2741. " * extension field number to fieldInfo object.\n"
  2742. " *\n"
  2743. " * For example:\n"
  2744. " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, "
  2745. "ctor: proto.example.MyMessage} }\n"
  2746. " *\n"
  2747. " * fieldName contains the JsCompiler renamed field name property "
  2748. "so that it\n"
  2749. " * works in OPTIMIZED mode.\n"
  2750. " *\n"
  2751. " * @type {!Object<number, jspb.ExtensionFieldBinaryInfo>}\n"
  2752. " */\n"
  2753. "$class$.extensionsBinary = {};\n"
  2754. "\n",
  2755. "class", GetMessagePath(options, desc));
  2756. }
  2757. }
  2758. void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options,
  2759. io::Printer* printer,
  2760. const Descriptor* desc) const {
  2761. // TODO(cfallin): Handle lazy decoding when requested by field option and/or
  2762. // by default for 'bytes' fields and packed repeated fields.
  2763. printer->Print(
  2764. "/**\n"
  2765. " * Deserializes binary data (in protobuf wire format).\n"
  2766. " * @param {jspb.ByteSource} bytes The bytes to deserialize.\n"
  2767. " * @return {!$class$}\n"
  2768. " */\n"
  2769. "$class$.deserializeBinary = function(bytes) {\n"
  2770. " var reader = new jspb.BinaryReader(bytes);\n"
  2771. " var msg = new $class$;\n"
  2772. " return $class$.deserializeBinaryFromReader(msg, reader);\n"
  2773. "};\n"
  2774. "\n"
  2775. "\n"
  2776. "/**\n"
  2777. " * Deserializes binary data (in protobuf wire format) from the\n"
  2778. " * given reader into the given message object.\n"
  2779. " * @param {!$class$} msg The message object to deserialize into.\n"
  2780. " * @param {!jspb.BinaryReader} reader The BinaryReader to use.\n"
  2781. " * @return {!$class$}\n"
  2782. " */\n"
  2783. "$class$.deserializeBinaryFromReader = function(msg, reader) {\n"
  2784. " while (reader.nextField()) {\n",
  2785. "class", GetMessagePath(options, desc));
  2786. printer->Print(
  2787. " if (reader.isEndGroup()) {\n"
  2788. " break;\n"
  2789. " }\n"
  2790. " var field = reader.getFieldNumber();\n"
  2791. " switch (field) {\n");
  2792. for (int i = 0; i < desc->field_count(); i++) {
  2793. if (!IgnoreField(desc->field(i))) {
  2794. GenerateClassDeserializeBinaryField(options, printer, desc->field(i));
  2795. }
  2796. }
  2797. printer->Print(" default:\n");
  2798. if (IsExtendable(desc)) {
  2799. printer->Print(
  2800. " jspb.Message.readBinaryExtension(msg, reader,\n"
  2801. " $extobj$Binary,\n"
  2802. " $class$.prototype.getExtension,\n"
  2803. " $class$.prototype.setExtension);\n"
  2804. " break;\n"
  2805. " }\n",
  2806. "extobj", JSExtensionsObjectName(options, desc->file(), desc), "class",
  2807. GetMessagePath(options, desc));
  2808. } else {
  2809. printer->Print(
  2810. " reader.skipField();\n"
  2811. " break;\n"
  2812. " }\n");
  2813. }
  2814. printer->Print(
  2815. " }\n"
  2816. " return msg;\n"
  2817. "};\n"
  2818. "\n"
  2819. "\n");
  2820. }
  2821. void Generator::GenerateClassDeserializeBinaryField(
  2822. const GeneratorOptions& options, io::Printer* printer,
  2823. const FieldDescriptor* field) const {
  2824. printer->Print(" case $num$:\n", "num", StrCat(field->number()));
  2825. if (field->is_map()) {
  2826. const FieldDescriptor* key_field = MapFieldKey(field);
  2827. const FieldDescriptor* value_field = MapFieldValue(field);
  2828. printer->Print(
  2829. " var value = msg.get$name$();\n"
  2830. " reader.readMessage(value, function(message, reader) {\n",
  2831. "name", JSGetterName(options, field));
  2832. printer->Print(
  2833. " jspb.Map.deserializeBinary(message, reader, "
  2834. "$keyReaderFn$, $valueReaderFn$",
  2835. "keyReaderFn", JSBinaryReaderMethodName(options, key_field),
  2836. "valueReaderFn", JSBinaryReaderMethodName(options, value_field));
  2837. if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
  2838. printer->Print(", $messageType$.deserializeBinaryFromReader",
  2839. "messageType",
  2840. GetMessagePath(options, value_field->message_type()));
  2841. } else {
  2842. printer->Print(", null");
  2843. }
  2844. printer->Print(", $defaultKey$", "defaultKey", JSFieldDefault(key_field));
  2845. if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
  2846. printer->Print(", new $messageType$()", "messageType",
  2847. GetMessagePath(options, value_field->message_type()));
  2848. } else {
  2849. printer->Print(", $defaultValue$", "defaultValue",
  2850. JSFieldDefault(value_field));
  2851. }
  2852. printer->Print(");\n");
  2853. printer->Print(" });\n");
  2854. } else {
  2855. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  2856. printer->Print(
  2857. " var value = new $fieldclass$;\n"
  2858. " reader.read$msgOrGroup$($grpfield$value,"
  2859. "$fieldclass$.deserializeBinaryFromReader);\n",
  2860. "fieldclass", SubmessageTypeRef(options, field), "msgOrGroup",
  2861. (field->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message",
  2862. "grpfield",
  2863. (field->type() == FieldDescriptor::TYPE_GROUP)
  2864. ? (StrCat(field->number()) + ", ")
  2865. : "");
  2866. } else if (field->is_packable()) {
  2867. printer->Print(
  2868. " var values = /** @type {$fieldtype$} */ "
  2869. "(reader.isDelimited() "
  2870. "? reader.readPacked$reader$() : [reader.read$reader$()]);\n",
  2871. "fieldtype",
  2872. JSFieldTypeAnnotation(options, field, false, true,
  2873. /* singular_if_not_packed */ false, BYTES_U8),
  2874. "reader", JSBinaryReaderMethodType(field));
  2875. } else {
  2876. printer->Print(
  2877. " var value = /** @type {$fieldtype$} */ "
  2878. "(reader.read$reader$());\n",
  2879. "fieldtype",
  2880. JSFieldTypeAnnotation(options, field, false, true,
  2881. /* singular_if_not_packed */ true, BYTES_U8),
  2882. "reader",
  2883. JSBinaryReadWriteMethodName(field, /* is_writer = */ false));
  2884. }
  2885. if (field->is_packable()) {
  2886. printer->Print(
  2887. " for (var i = 0; i < values.length; i++) {\n"
  2888. " msg.add$name$(values[i]);\n"
  2889. " }\n",
  2890. "name",
  2891. JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true));
  2892. } else if (field->is_repeated()) {
  2893. printer->Print(
  2894. " msg.add$name$(value);\n", "name",
  2895. JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true));
  2896. } else {
  2897. // Singular fields, and packed repeated fields, receive a |value| either
  2898. // as the field's value or as the array of all the field's values; set
  2899. // this as the field's value directly.
  2900. printer->Print(" msg.set$name$(value);\n", "name",
  2901. JSGetterName(options, field));
  2902. }
  2903. }
  2904. printer->Print(" break;\n");
  2905. }
  2906. void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options,
  2907. io::Printer* printer,
  2908. const Descriptor* desc) const {
  2909. printer->Print(
  2910. "/**\n"
  2911. " * Serializes the message to binary data (in protobuf wire format).\n"
  2912. " * @return {!Uint8Array}\n"
  2913. " */\n"
  2914. "$class$.prototype.serializeBinary = function() {\n"
  2915. " var writer = new jspb.BinaryWriter();\n"
  2916. " $class$.serializeBinaryToWriter(this, writer);\n"
  2917. " return writer.getResultBuffer();\n"
  2918. "};\n"
  2919. "\n"
  2920. "\n"
  2921. "/**\n"
  2922. " * Serializes the given message to binary data (in protobuf wire\n"
  2923. " * format), writing to the given BinaryWriter.\n"
  2924. " * @param {!$class$} message\n"
  2925. " * @param {!jspb.BinaryWriter} writer\n"
  2926. " * @suppress {unusedLocalVariables} f is only used for nested messages\n"
  2927. " */\n"
  2928. "$class$.serializeBinaryToWriter = function(message, "
  2929. "writer) {\n"
  2930. " var f = undefined;\n",
  2931. "class", GetMessagePath(options, desc));
  2932. for (int i = 0; i < desc->field_count(); i++) {
  2933. if (!IgnoreField(desc->field(i))) {
  2934. GenerateClassSerializeBinaryField(options, printer, desc->field(i));
  2935. }
  2936. }
  2937. if (IsExtendable(desc)) {
  2938. printer->Print(
  2939. " jspb.Message.serializeBinaryExtensions(message, writer,\n"
  2940. " $extobj$Binary, $class$.prototype.getExtension);\n",
  2941. "extobj", JSExtensionsObjectName(options, desc->file(), desc), "class",
  2942. GetMessagePath(options, desc));
  2943. }
  2944. printer->Print(
  2945. "};\n"
  2946. "\n"
  2947. "\n");
  2948. }
  2949. void Generator::GenerateClassSerializeBinaryField(
  2950. const GeneratorOptions& options, io::Printer* printer,
  2951. const FieldDescriptor* field) const {
  2952. if (HasFieldPresence(options, field) &&
  2953. field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
  2954. std::string typed_annotation =
  2955. JSFieldTypeAnnotation(options, field,
  2956. /* is_setter_argument = */ false,
  2957. /* force_present = */ false,
  2958. /* singular_if_not_packed = */ false,
  2959. /* bytes_mode = */ BYTES_DEFAULT);
  2960. printer->Print(
  2961. " f = /** @type {$type$} */ "
  2962. "(jspb.Message.getField(message, $index$));\n",
  2963. "index", JSFieldIndex(field), "type", typed_annotation);
  2964. } else {
  2965. printer->Print(
  2966. " f = message.get$name$($nolazy$);\n", "name",
  2967. JSGetterName(options, field, BYTES_U8),
  2968. // No lazy creation for maps containers -- fastpath the empty case.
  2969. "nolazy", field->is_map() ? "true" : "");
  2970. }
  2971. // Print an `if (condition)` statement that evaluates to true if the field
  2972. // goes on the wire.
  2973. if (field->is_map()) {
  2974. printer->Print(" if (f && f.getLength() > 0) {\n");
  2975. } else if (field->is_repeated()) {
  2976. printer->Print(" if (f.length > 0) {\n");
  2977. } else {
  2978. if (HasFieldPresence(options, field)) {
  2979. printer->Print(" if (f != null) {\n");
  2980. } else {
  2981. // No field presence: serialize onto the wire only if value is
  2982. // non-default. Defaults are documented here:
  2983. // https://goto.google.com/lhdfm
  2984. switch (field->cpp_type()) {
  2985. case FieldDescriptor::CPPTYPE_INT32:
  2986. case FieldDescriptor::CPPTYPE_INT64:
  2987. case FieldDescriptor::CPPTYPE_UINT32:
  2988. case FieldDescriptor::CPPTYPE_UINT64: {
  2989. if (IsIntegralFieldWithStringJSType(field)) {
  2990. // We can use `parseInt` here even though it will not be precise for
  2991. // 64-bit quantities because we are only testing for zero/nonzero,
  2992. // and JS numbers (64-bit floating point values, i.e., doubles) are
  2993. // integer-precise in the range that includes zero.
  2994. printer->Print(" if (parseInt(f, 10) !== 0) {\n");
  2995. } else {
  2996. printer->Print(" if (f !== 0) {\n");
  2997. }
  2998. break;
  2999. }
  3000. case FieldDescriptor::CPPTYPE_ENUM:
  3001. case FieldDescriptor::CPPTYPE_FLOAT:
  3002. case FieldDescriptor::CPPTYPE_DOUBLE:
  3003. printer->Print(" if (f !== 0.0) {\n");
  3004. break;
  3005. case FieldDescriptor::CPPTYPE_BOOL:
  3006. printer->Print(" if (f) {\n");
  3007. break;
  3008. case FieldDescriptor::CPPTYPE_STRING:
  3009. printer->Print(" if (f.length > 0) {\n");
  3010. break;
  3011. default:
  3012. assert(false);
  3013. break;
  3014. }
  3015. }
  3016. }
  3017. // Write the field on the wire.
  3018. if (field->is_map()) {
  3019. const FieldDescriptor* key_field = MapFieldKey(field);
  3020. const FieldDescriptor* value_field = MapFieldValue(field);
  3021. printer->Print(
  3022. " f.serializeBinary($index$, writer, "
  3023. "$keyWriterFn$, $valueWriterFn$",
  3024. "index", StrCat(field->number()), "keyWriterFn",
  3025. JSBinaryWriterMethodName(options, key_field), "valueWriterFn",
  3026. JSBinaryWriterMethodName(options, value_field));
  3027. if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
  3028. printer->Print(", $messageType$.serializeBinaryToWriter", "messageType",
  3029. GetMessagePath(options, value_field->message_type()));
  3030. }
  3031. printer->Print(");\n");
  3032. } else {
  3033. printer->Print(
  3034. " writer.write$method$(\n"
  3035. " $index$,\n"
  3036. " f",
  3037. "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true),
  3038. "index", StrCat(field->number()));
  3039. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
  3040. !field->is_map()) {
  3041. printer->Print(
  3042. ",\n"
  3043. " $submsg$.serializeBinaryToWriter\n",
  3044. "submsg", SubmessageTypeRef(options, field));
  3045. } else {
  3046. printer->Print("\n");
  3047. }
  3048. printer->Print(" );\n");
  3049. }
  3050. // Close the `if`.
  3051. printer->Print(" }\n");
  3052. }
  3053. void Generator::GenerateEnum(const GeneratorOptions& options,
  3054. io::Printer* printer,
  3055. const EnumDescriptor* enumdesc) const {
  3056. printer->Print(
  3057. "/**\n"
  3058. " * @enum {number}\n"
  3059. " */\n"
  3060. "$enumprefix$$name$ = {\n",
  3061. "enumprefix", GetEnumPathPrefix(options, enumdesc), "name",
  3062. enumdesc->name());
  3063. printer->Annotate("name", enumdesc);
  3064. std::set<std::string> used_name;
  3065. std::vector<int> valid_index;
  3066. for (int i = 0; i < enumdesc->value_count(); i++) {
  3067. if (enumdesc->options().allow_alias() &&
  3068. !used_name.insert(ToEnumCase(enumdesc->value(i)->name())).second) {
  3069. continue;
  3070. }
  3071. valid_index.push_back(i);
  3072. }
  3073. for (auto i : valid_index) {
  3074. const EnumValueDescriptor* value = enumdesc->value(i);
  3075. printer->Print(" $name$: $value$$comma$\n", "name",
  3076. ToEnumCase(value->name()), "value", StrCat(value->number()),
  3077. "comma", (i == valid_index.back()) ? "" : ",");
  3078. printer->Annotate("name", value);
  3079. }
  3080. printer->Print(
  3081. "};\n"
  3082. "\n");
  3083. }
  3084. void Generator::GenerateExtension(const GeneratorOptions& options,
  3085. io::Printer* printer,
  3086. const FieldDescriptor* field) const {
  3087. std::string extension_scope =
  3088. (field->extension_scope()
  3089. ? GetMessagePath(options, field->extension_scope())
  3090. : GetNamespace(options, field->file()));
  3091. const std::string extension_object_name = JSObjectFieldName(options, field);
  3092. printer->Print(
  3093. "\n"
  3094. "/**\n"
  3095. " * A tuple of {field number, class constructor} for the extension\n"
  3096. " * field named `$nameInComment$`.\n"
  3097. " * @type {!jspb.ExtensionFieldInfo<$extensionType$>}\n"
  3098. " */\n"
  3099. "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
  3100. "nameInComment", extension_object_name, "name", extension_object_name,
  3101. "class", extension_scope, "extensionType",
  3102. JSFieldTypeAnnotation(options, field,
  3103. /* is_setter_argument = */ false,
  3104. /* force_present = */ true,
  3105. /* singular_if_not_packed = */ false));
  3106. printer->Annotate("name", field);
  3107. printer->Print(
  3108. " $index$,\n"
  3109. " {$name$: 0},\n"
  3110. " $ctor$,\n"
  3111. " /** @type {?function((boolean|undefined),!jspb.Message=): "
  3112. "!Object} */ (\n"
  3113. " $toObject$),\n"
  3114. " $repeated$);\n",
  3115. "index", StrCat(field->number()), "name", extension_object_name, "ctor",
  3116. (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
  3117. ? SubmessageTypeRef(options, field)
  3118. : std::string("null")),
  3119. "toObject",
  3120. (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
  3121. ? (SubmessageTypeRef(options, field) + ".toObject")
  3122. : std::string("null")),
  3123. "repeated", (field->is_repeated() ? "1" : "0"));
  3124. printer->Print(
  3125. "\n"
  3126. "$extendName$Binary[$index$] = new jspb.ExtensionFieldBinaryInfo(\n"
  3127. " $class$.$name$,\n"
  3128. " $binaryReaderFn$,\n"
  3129. " $binaryWriterFn$,\n"
  3130. " $binaryMessageSerializeFn$,\n"
  3131. " $binaryMessageDeserializeFn$,\n",
  3132. "extendName",
  3133. JSExtensionsObjectName(options, field->file(), field->containing_type()),
  3134. "index", StrCat(field->number()), "class", extension_scope, "name",
  3135. extension_object_name, "binaryReaderFn",
  3136. JSBinaryReaderMethodName(options, field), "binaryWriterFn",
  3137. JSBinaryWriterMethodName(options, field), "binaryMessageSerializeFn",
  3138. (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
  3139. ? (SubmessageTypeRef(options, field) + ".serializeBinaryToWriter")
  3140. : "undefined",
  3141. "binaryMessageDeserializeFn",
  3142. (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
  3143. ? (SubmessageTypeRef(options, field) + ".deserializeBinaryFromReader")
  3144. : "undefined");
  3145. printer->Print(" $isPacked$);\n", "isPacked",
  3146. (field->is_packed() ? "true" : "false"));
  3147. printer->Print(
  3148. "// This registers the extension field with the extended class, so that\n"
  3149. "// toObject() will function correctly.\n"
  3150. "$extendName$[$index$] = $class$.$name$;\n"
  3151. "\n",
  3152. "extendName",
  3153. JSExtensionsObjectName(options, field->file(), field->containing_type()),
  3154. "index", StrCat(field->number()), "class", extension_scope, "name",
  3155. extension_object_name);
  3156. }
  3157. bool GeneratorOptions::ParseFromOptions(
  3158. const std::vector<std::pair<std::string, std::string> >& options,
  3159. std::string* error) {
  3160. for (int i = 0; i < options.size(); i++) {
  3161. if (options[i].first == "add_require_for_enums") {
  3162. if (options[i].second != "") {
  3163. *error = "Unexpected option value for add_require_for_enums";
  3164. return false;
  3165. }
  3166. add_require_for_enums = true;
  3167. } else if (options[i].first == "binary") {
  3168. if (options[i].second != "") {
  3169. *error = "Unexpected option value for binary";
  3170. return false;
  3171. }
  3172. binary = true;
  3173. } else if (options[i].first == "testonly") {
  3174. if (options[i].second != "") {
  3175. *error = "Unexpected option value for testonly";
  3176. return false;
  3177. }
  3178. testonly = true;
  3179. } else if (options[i].first == "error_on_name_conflict") {
  3180. if (options[i].second != "") {
  3181. *error = "Unexpected option value for error_on_name_conflict";
  3182. return false;
  3183. }
  3184. error_on_name_conflict = true;
  3185. } else if (options[i].first == "output_dir") {
  3186. output_dir = options[i].second;
  3187. } else if (options[i].first == "namespace_prefix") {
  3188. namespace_prefix = options[i].second;
  3189. } else if (options[i].first == "library") {
  3190. library = options[i].second;
  3191. } else if (options[i].first == "import_style") {
  3192. if (options[i].second == "closure") {
  3193. import_style = kImportClosure;
  3194. } else if (options[i].second == "commonjs") {
  3195. import_style = kImportCommonJs;
  3196. } else if (options[i].second == "commonjs_strict") {
  3197. import_style = kImportCommonJsStrict;
  3198. } else if (options[i].second == "browser") {
  3199. import_style = kImportBrowser;
  3200. } else if (options[i].second == "es6") {
  3201. import_style = kImportEs6;
  3202. } else {
  3203. *error = "Unknown import style " + options[i].second + ", expected " +
  3204. "one of: closure, commonjs, browser, es6.";
  3205. }
  3206. } else if (options[i].first == "extension") {
  3207. extension = options[i].second;
  3208. } else if (options[i].first == "one_output_file_per_input_file") {
  3209. if (!options[i].second.empty()) {
  3210. *error = "Unexpected option value for one_output_file_per_input_file";
  3211. return false;
  3212. }
  3213. one_output_file_per_input_file = true;
  3214. } else if (options[i].first == "annotate_code") {
  3215. if (!options[i].second.empty()) {
  3216. *error = "Unexpected option value for annotate_code";
  3217. return false;
  3218. }
  3219. annotate_code = true;
  3220. } else {
  3221. // Assume any other option is an output directory, as long as it is a bare
  3222. // `key` rather than a `key=value` option.
  3223. if (options[i].second != "") {
  3224. *error = "Unknown option: " + options[i].first;
  3225. return false;
  3226. }
  3227. output_dir = options[i].first;
  3228. }
  3229. }
  3230. if (import_style != kImportClosure &&
  3231. (add_require_for_enums || testonly || !library.empty() ||
  3232. error_on_name_conflict || extension != ".js" ||
  3233. one_output_file_per_input_file)) {
  3234. *error =
  3235. "The add_require_for_enums, testonly, library, error_on_name_conflict, "
  3236. "extension, and one_output_file_per_input_file options should only be "
  3237. "used for import_style=closure";
  3238. return false;
  3239. }
  3240. return true;
  3241. }
  3242. GeneratorOptions::OutputMode GeneratorOptions::output_mode() const {
  3243. // We use one output file per input file if we are not using Closure or if
  3244. // this is explicitly requested.
  3245. if (import_style != kImportClosure || one_output_file_per_input_file) {
  3246. return kOneOutputFilePerInputFile;
  3247. }
  3248. // If a library name is provided, we put everything in that one file.
  3249. if (!library.empty()) {
  3250. return kEverythingInOneFile;
  3251. }
  3252. // Otherwise, we create one output file per SCC.
  3253. return kOneOutputFilePerSCC;
  3254. }
  3255. void Generator::GenerateFilesInDepOrder(
  3256. const GeneratorOptions& options, io::Printer* printer,
  3257. const std::vector<const FileDescriptor*>& files) const {
  3258. // Build a std::set over all files so that the DFS can detect when it recurses
  3259. // into a dep not specified in the user's command line.
  3260. std::set<const FileDescriptor*> all_files(files.begin(), files.end());
  3261. // Track the in-progress set of files that have been generated already.
  3262. std::set<const FileDescriptor*> generated;
  3263. for (int i = 0; i < files.size(); i++) {
  3264. GenerateFileAndDeps(options, printer, files[i], &all_files, &generated);
  3265. }
  3266. }
  3267. void Generator::GenerateFileAndDeps(
  3268. const GeneratorOptions& options, io::Printer* printer,
  3269. const FileDescriptor* root, std::set<const FileDescriptor*>* all_files,
  3270. std::set<const FileDescriptor*>* generated) const {
  3271. // Skip if already generated.
  3272. if (generated->find(root) != generated->end()) {
  3273. return;
  3274. }
  3275. generated->insert(root);
  3276. // Generate all dependencies before this file's content.
  3277. for (int i = 0; i < root->dependency_count(); i++) {
  3278. const FileDescriptor* dep = root->dependency(i);
  3279. GenerateFileAndDeps(options, printer, dep, all_files, generated);
  3280. }
  3281. // Generate this file's content. Only generate if the file is part of the
  3282. // original set requested to be generated; i.e., don't take all transitive
  3283. // deps down to the roots.
  3284. if (all_files->find(root) != all_files->end()) {
  3285. GenerateClassesAndEnums(options, printer, root);
  3286. }
  3287. }
  3288. bool Generator::GenerateFile(const FileDescriptor* file,
  3289. const GeneratorOptions& options,
  3290. GeneratorContext* context,
  3291. bool use_short_name) const {
  3292. std::string filename =
  3293. options.output_dir + "/" +
  3294. GetJSFilename(options, use_short_name
  3295. ? file->name().substr(file->name().rfind('/'))
  3296. : file->name());
  3297. std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
  3298. GOOGLE_CHECK(output);
  3299. GeneratedCodeInfo annotations;
  3300. io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
  3301. &annotations);
  3302. io::Printer printer(output.get(), '$',
  3303. options.annotate_code ? &annotation_collector : nullptr);
  3304. GenerateFile(options, &printer, file);
  3305. if (printer.failed()) {
  3306. return false;
  3307. }
  3308. if (options.annotate_code) {
  3309. EmbedCodeAnnotations(annotations, &printer);
  3310. }
  3311. return true;
  3312. }
  3313. void Generator::GenerateFile(const GeneratorOptions& options,
  3314. io::Printer* printer,
  3315. const FileDescriptor* file) const {
  3316. GenerateHeader(options, file, printer);
  3317. // Generate "require" statements.
  3318. if ((options.import_style == GeneratorOptions::kImportCommonJs ||
  3319. options.import_style == GeneratorOptions::kImportCommonJsStrict)) {
  3320. printer->Print("var jspb = require('google-protobuf');\n");
  3321. printer->Print("var goog = jspb;\n");
  3322. // Do not use global scope in strict mode
  3323. if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
  3324. printer->Print("var proto = {};\n\n");
  3325. } else {
  3326. printer->Print("var global = Function('return this')();\n\n");
  3327. }
  3328. for (int i = 0; i < file->dependency_count(); i++) {
  3329. const std::string& name = file->dependency(i)->name();
  3330. printer->Print(
  3331. "var $alias$ = require('$file$');\n"
  3332. "goog.object.extend(proto, $alias$);\n",
  3333. "alias", ModuleAlias(name), "file",
  3334. GetRootPath(file->name(), name) + GetJSFilename(options, name));
  3335. }
  3336. }
  3337. std::set<std::string> provided;
  3338. std::set<const FieldDescriptor*> extensions;
  3339. for (int i = 0; i < file->extension_count(); i++) {
  3340. // We honor the jspb::ignore option here only when working with
  3341. // Closure-style imports. Use of this option is discouraged and so we want
  3342. // to avoid adding new support for it.
  3343. if (options.import_style == GeneratorOptions::kImportClosure &&
  3344. IgnoreField(file->extension(i))) {
  3345. continue;
  3346. }
  3347. provided.insert(GetNamespace(options, file) + "." +
  3348. JSObjectFieldName(options, file->extension(i)));
  3349. extensions.insert(file->extension(i));
  3350. }
  3351. FindProvidesForFile(options, printer, file, &provided);
  3352. GenerateProvides(options, printer, &provided);
  3353. std::vector<const FileDescriptor*> files;
  3354. files.push_back(file);
  3355. if (options.import_style == GeneratorOptions::kImportClosure) {
  3356. GenerateRequiresForLibrary(options, printer, files, &provided);
  3357. }
  3358. GenerateClassesAndEnums(options, printer, file);
  3359. // Generate code for top-level extensions. Extensions nested inside messages
  3360. // are emitted inside GenerateClassesAndEnums().
  3361. for (std::set<const FieldDescriptor*>::const_iterator it = extensions.begin();
  3362. it != extensions.end(); ++it) {
  3363. GenerateExtension(options, printer, *it);
  3364. }
  3365. // if provided is empty, do not export anything
  3366. if (options.import_style == GeneratorOptions::kImportCommonJs &&
  3367. !provided.empty()) {
  3368. printer->Print("goog.object.extend(exports, $package$);\n", "package",
  3369. GetNamespace(options, file));
  3370. } else if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
  3371. printer->Print("goog.object.extend(exports, proto);\n", "package",
  3372. GetNamespace(options, file));
  3373. }
  3374. // Emit well-known type methods.
  3375. for (FileToc* toc = well_known_types_js; toc->name != NULL; toc++) {
  3376. std::string name = std::string("google/protobuf/") + toc->name;
  3377. if (name == StripProto(file->name()) + ".js") {
  3378. printer->Print(toc->data);
  3379. }
  3380. }
  3381. }
  3382. bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
  3383. const std::string& parameter,
  3384. GeneratorContext* context,
  3385. std::string* error) const {
  3386. std::vector<std::pair<std::string, std::string> > option_pairs;
  3387. ParseGeneratorParameter(parameter, &option_pairs);
  3388. GeneratorOptions options;
  3389. if (!options.ParseFromOptions(option_pairs, error)) {
  3390. return false;
  3391. }
  3392. if (options.output_mode() == GeneratorOptions::kEverythingInOneFile) {
  3393. // All output should go in a single file.
  3394. std::string filename = options.output_dir + "/" + options.library +
  3395. options.GetFileNameExtension();
  3396. std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
  3397. GOOGLE_CHECK(output.get());
  3398. GeneratedCodeInfo annotations;
  3399. io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
  3400. &annotations);
  3401. io::Printer printer(
  3402. output.get(), '$',
  3403. options.annotate_code ? &annotation_collector : nullptr);
  3404. // Pull out all extensions -- we need these to generate all
  3405. // provides/requires.
  3406. std::vector<const FieldDescriptor*> extensions;
  3407. for (int i = 0; i < files.size(); i++) {
  3408. for (int j = 0; j < files[i]->extension_count(); j++) {
  3409. const FieldDescriptor* extension = files[i]->extension(j);
  3410. extensions.push_back(extension);
  3411. }
  3412. }
  3413. if (files.size() == 1) {
  3414. GenerateHeader(options, files[0], &printer);
  3415. } else {
  3416. GenerateHeader(options, nullptr, &printer);
  3417. }
  3418. std::set<std::string> provided;
  3419. FindProvides(options, &printer, files, &provided);
  3420. FindProvidesForFields(options, &printer, extensions, &provided);
  3421. GenerateProvides(options, &printer, &provided);
  3422. GenerateTestOnly(options, &printer);
  3423. GenerateRequiresForLibrary(options, &printer, files, &provided);
  3424. GenerateFilesInDepOrder(options, &printer, files);
  3425. for (int i = 0; i < extensions.size(); i++) {
  3426. if (ShouldGenerateExtension(extensions[i])) {
  3427. GenerateExtension(options, &printer, extensions[i]);
  3428. }
  3429. }
  3430. if (printer.failed()) {
  3431. return false;
  3432. }
  3433. if (options.annotate_code) {
  3434. EmbedCodeAnnotations(annotations, &printer);
  3435. }
  3436. } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerSCC) {
  3437. std::set<const Descriptor*> have_printed;
  3438. SCCAnalyzer<DepsGenerator> analyzer;
  3439. std::map<const void*, std::string> allowed_map;
  3440. if (!GenerateJspbAllowedMap(options, files, &allowed_map, &analyzer,
  3441. error)) {
  3442. return false;
  3443. }
  3444. bool generated = false;
  3445. for (int i = 0; i < files.size(); i++) {
  3446. const FileDescriptor* file = files[i];
  3447. // Force well known type to generate in a whole file.
  3448. if (IsWellKnownTypeFile(file)) {
  3449. if (!GenerateFile(file, options, context, true)) {
  3450. return false;
  3451. }
  3452. generated = true;
  3453. continue;
  3454. }
  3455. for (int j = 0; j < file->message_type_count(); j++) {
  3456. const Descriptor* desc = file->message_type(j);
  3457. if (have_printed.count(desc) ||
  3458. allowed_map.count(analyzer.GetSCC(desc)) == 0) {
  3459. continue;
  3460. }
  3461. generated = true;
  3462. const SCC* scc = analyzer.GetSCC(desc);
  3463. const std::string& filename = allowed_map[scc];
  3464. std::unique_ptr<io::ZeroCopyOutputStream> output(
  3465. context->Open(filename));
  3466. GOOGLE_CHECK(output.get());
  3467. GeneratedCodeInfo annotations;
  3468. io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
  3469. &annotations);
  3470. io::Printer printer(
  3471. output.get(), '$',
  3472. options.annotate_code ? &annotation_collector : nullptr);
  3473. GenerateHeader(options, file, &printer);
  3474. std::set<std::string> provided;
  3475. for (auto one_desc : scc->descriptors) {
  3476. if (one_desc->containing_type() == nullptr) {
  3477. FindProvidesForMessage(options, &printer, one_desc, &provided);
  3478. }
  3479. }
  3480. GenerateProvides(options, &printer, &provided);
  3481. GenerateTestOnly(options, &printer);
  3482. GenerateRequiresForSCC(options, &printer, scc, &provided);
  3483. for (auto one_desc : scc->descriptors) {
  3484. if (one_desc->containing_type() == nullptr) {
  3485. GenerateClassConstructorAndDeclareExtensionFieldInfo(
  3486. options, &printer, one_desc);
  3487. }
  3488. }
  3489. for (auto one_desc : scc->descriptors) {
  3490. if (one_desc->containing_type() == nullptr) {
  3491. GenerateClass(options, &printer, one_desc);
  3492. }
  3493. }
  3494. for (auto one_desc : scc->descriptors) {
  3495. have_printed.insert(one_desc);
  3496. }
  3497. if (printer.failed()) {
  3498. return false;
  3499. }
  3500. if (options.annotate_code) {
  3501. EmbedCodeAnnotations(annotations, &printer);
  3502. }
  3503. }
  3504. for (int j = 0; j < file->enum_type_count(); j++) {
  3505. const EnumDescriptor* enumdesc = file->enum_type(j);
  3506. if (allowed_map.count(enumdesc) == 0) {
  3507. continue;
  3508. }
  3509. generated = true;
  3510. const std::string& filename = allowed_map[enumdesc];
  3511. std::unique_ptr<io::ZeroCopyOutputStream> output(
  3512. context->Open(filename));
  3513. GOOGLE_CHECK(output.get());
  3514. GeneratedCodeInfo annotations;
  3515. io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
  3516. &annotations);
  3517. io::Printer printer(
  3518. output.get(), '$',
  3519. options.annotate_code ? &annotation_collector : nullptr);
  3520. GenerateHeader(options, file, &printer);
  3521. std::set<std::string> provided;
  3522. FindProvidesForEnum(options, &printer, enumdesc, &provided);
  3523. GenerateProvides(options, &printer, &provided);
  3524. GenerateTestOnly(options, &printer);
  3525. GenerateEnum(options, &printer, enumdesc);
  3526. if (printer.failed()) {
  3527. return false;
  3528. }
  3529. if (options.annotate_code) {
  3530. EmbedCodeAnnotations(annotations, &printer);
  3531. }
  3532. }
  3533. // File-level extensions (message-level extensions are generated under
  3534. // the enclosing message).
  3535. if (allowed_map.count(file) == 1) {
  3536. generated = true;
  3537. const std::string& filename = allowed_map[file];
  3538. std::unique_ptr<io::ZeroCopyOutputStream> output(
  3539. context->Open(filename));
  3540. GOOGLE_CHECK(output.get());
  3541. GeneratedCodeInfo annotations;
  3542. io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
  3543. &annotations);
  3544. io::Printer printer(
  3545. output.get(), '$',
  3546. options.annotate_code ? &annotation_collector : nullptr);
  3547. GenerateHeader(options, file, &printer);
  3548. std::set<std::string> provided;
  3549. std::vector<const FieldDescriptor*> fields;
  3550. for (int j = 0; j < files[i]->extension_count(); j++) {
  3551. if (ShouldGenerateExtension(files[i]->extension(j))) {
  3552. fields.push_back(files[i]->extension(j));
  3553. }
  3554. }
  3555. FindProvidesForFields(options, &printer, fields, &provided);
  3556. GenerateProvides(options, &printer, &provided);
  3557. GenerateTestOnly(options, &printer);
  3558. GenerateRequiresForExtensions(options, &printer, fields, &provided);
  3559. for (int j = 0; j < files[i]->extension_count(); j++) {
  3560. if (ShouldGenerateExtension(files[i]->extension(j))) {
  3561. GenerateExtension(options, &printer, files[i]->extension(j));
  3562. }
  3563. }
  3564. if (options.annotate_code) {
  3565. EmbedCodeAnnotations(annotations, &printer);
  3566. }
  3567. }
  3568. }
  3569. if (!generated) {
  3570. std::string filename = options.output_dir + "/" +
  3571. "empty_no_content_void_file" +
  3572. options.GetFileNameExtension();
  3573. std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
  3574. }
  3575. } else /* options.output_mode() == kOneOutputFilePerInputFile */ {
  3576. // Generate one output file per input (.proto) file.
  3577. for (int i = 0; i < files.size(); i++) {
  3578. const FileDescriptor* file = files[i];
  3579. if (!GenerateFile(file, options, context, false)) {
  3580. return false;
  3581. }
  3582. }
  3583. }
  3584. return true;
  3585. }
  3586. } // namespace js
  3587. } // namespace compiler
  3588. } // namespace protobuf
  3589. } // namespace google