js_generator.cc 126 KB

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