OLD | NEW |
---|---|
(Empty) | |
1 <!-- | |
2 Copyright 2016 The Chromium Authors. All rights reserved. | |
3 Use of this source code is governed by a BSD-style license that can be | |
4 found in the LICENSE file. | |
5 --> | |
6 | |
7 <!-- | |
8 rpcExplorer.descUtil exposes helper methods to work with protobuf | |
9 descriptor messages. | |
10 Primarily it implements name and comments resolution in a FileDescriptorSet. | |
11 --> | |
12 <script> | |
13 'use strict'; | |
14 | |
15 var rpcExplorer = (function(rpcExplorer) { | |
16 | |
17 rpcExplorer.descUtil = { | |
18 | |
19 /** | |
20 * for all descriptors in the file annotate resolves | |
21 * SourceLocationInfo.Location message and assigns it to source_code_info | |
Bons
2016/02/23 15:52:28
assigns it to THE
nodir
2016/02/23 18:32:25
Done.
| |
22 * property of the descriptor. | |
23 * Prerequisite reading: | |
24 * https://github.com/luci/luci-go/blob/ea240d0/common/proto/google/descript or/descriptor.proto#L713 | |
25 * @param {FileDescriptorProto} file | |
26 */ | |
27 annotate: function(file) { | |
28 if (!file.source_code_info) { | |
29 return; | |
30 } | |
31 | |
32 // First, build a map { path -> location message }. | |
33 function key(path) { | |
34 var key = ''; | |
35 for (var i = 0; i < path.length; i++) { | |
36 key += path[i] + '.'; | |
37 } | |
38 return key; | |
39 } | |
40 var locationMap = {}; | |
41 for (var i = 0; i < file.source_code_info.location.length; i++) { | |
42 var loc = file.source_code_info.location[i]; | |
43 if (loc.path) { | |
44 locationMap[key(loc.path)] = loc; | |
45 } | |
46 } | |
47 | |
48 // Now join all descriptors in file with the map. | |
49 var path = []; | |
50 | |
51 function annotateList(list, field, fn) { | |
52 if (!list) { | |
53 return; | |
54 } | |
55 path.push(field, 0); | |
56 for (var i = 0; i < list.length; i++) { | |
57 path[path.length - 1] = i; | |
58 list[i].source_code_info = locationMap[key(path)]; | |
59 if (fn) { | |
60 fn(list[i]); | |
61 } | |
62 } | |
63 path.pop(); | |
64 path.pop(); | |
65 } | |
66 | |
67 // The magic numbers below are message field numbers defined in | |
68 // descriptor.proto. | |
69 | |
70 function annotateMessage(msg) { | |
71 annotateList(msg.field, 2); | |
72 annotateList(msg.nested_type, 3, annotateMessage); | |
73 annotateList(msg.enum_type, 4, annotateEnum); | |
74 } | |
75 | |
76 function annotateEnum(e) { | |
77 annotateList(e.value, 2); | |
78 } | |
79 | |
80 function annotateService(svc) { | |
81 annotateList(svc.method, 2); | |
82 } | |
83 | |
84 annotateList(file.message_type, 4, annotateMessage); | |
85 annotateList(file.enum_type, 5, annotateEnum); | |
86 annotateList(file.service, 6, annotateService); | |
87 }, | |
88 | |
89 /** | |
90 * Annotates a FileDescriptorSet. | |
91 */ | |
92 annotateSet: function(fileSet) { | |
93 for (var i = 0; i < fileSet.file.length; i++) { | |
94 this.annotate(fileSet.file[i]); | |
95 } | |
96 }, | |
97 | |
98 splitFullName: function(fullName) { | |
99 var lastDot = fullName.lastIndexOf('.'); | |
100 if (lastDot === -1) { | |
101 return { | |
102 pkg: '', | |
103 name: fullName | |
104 }; | |
105 } | |
106 | |
107 return { | |
108 pkg: fullName.substr(0, lastDot), | |
109 name: fullName.substr(lastDot + 1) | |
110 }; | |
111 }, | |
112 | |
113 /** | |
114 * Resolves services, methods, messages, fields, enums and enum values. | |
115 */ | |
116 resolve: function(desc, name) { | |
117 if (!desc || !name) { | |
118 return null; | |
119 } | |
120 name = this.splitFullName(name); | |
121 | |
122 var self = this; | |
123 | |
124 // searches in each list. | |
125 function checkLists(lists) { | |
126 if (!lists) { | |
127 return null; | |
128 } | |
129 for (var type in lists) { | |
130 var desc = self.findByName(lists[type], name.name); | |
131 if (desc) { | |
132 return {type: type, desc: desc }; | |
133 } | |
134 } | |
135 return null; | |
136 } | |
137 | |
138 // Check top-level descriptors. | |
139 for (var i = 0; i < desc.file.length; i++) { | |
140 var file = desc.file[i]; | |
141 if (file['package'] != name.pkg) { | |
142 continue | |
143 } | |
144 | |
145 var result = checkLists({ | |
146 service: file.service, | |
147 messageType: file.message_type, | |
148 enumType: file.enum_type | |
149 }); | |
150 if (result) { | |
151 return result; | |
152 } | |
153 } | |
154 | |
155 // Recurse. | |
Bons
2016/02/23 15:52:28
be more descriptive with these comments if they ne
nodir
2016/02/23 18:32:25
Done.
| |
156 var parent = this.resolve(desc, name.pkg); | |
157 if (!parent) { | |
158 return null; | |
159 } | |
160 switch (parent.type) { | |
161 case 'service': | |
162 return checkLists({ method: parent.desc.method }); | |
163 | |
164 case 'messageType': | |
165 return checkLists({ | |
166 field: parent.desc.field, | |
167 messageType: parent.desc.nested_type, | |
168 enumType: parent.desc.enum_type | |
169 }); | |
170 | |
171 case 'enumType': | |
172 return checkLists({ | |
173 enumValue: parent.desc.value, | |
174 }); | |
175 | |
176 default: | |
177 return null; | |
178 } | |
179 }, | |
180 | |
181 findByName: function(array, name) { | |
182 if (!array) { | |
183 return null; | |
184 } | |
185 for (var i = 0; i < array.length; i++) { | |
186 if (array[i].name === name) { | |
187 return array[i]; | |
188 } | |
189 } | |
190 return null; | |
191 }, | |
192 | |
193 trimPrefixDot: function(name) { | |
194 if (typeof name === 'string' && name.charAt(0) === '.') { | |
195 name = name.substr(1); | |
196 } | |
197 return name; | |
198 } | |
199 }; | |
200 | |
201 return rpcExplorer; | |
202 }(rpcExplorer || {})); | |
203 </script> | |
OLD | NEW |