Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Side by Side Diff: pkg/analysis_server/spec/api.dart

Issue 443873006: Add analysis server API specification and related tools. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * Data structures representing an API definition, and visitor base classes
7 * for visiting those data structures.
8 */
9 library api;
10
11 import 'dart:collection';
12
13 import 'package:html5lib/dom.dart' as dom;
14
15 /**
16 * Base class for visiting the API definition.
17 */
18 abstract class ApiVisitor<T> {
19 T visitTypeReference(TypeReference typeReference);
20 T visitTypeObject(TypeObject typeObject);
21 T visitTypeList(TypeList typeList);
22 T visitTypeMap(TypeMap typeMap);
23 T visitTypeEnum(TypeEnum typeEnum);
24
25 /**
26 * Dispatch the given [node] to the visitor.
scheglov 2014/08/06 18:20:39 [node] -> [type]
Paul Berry 2014/08/06 18:32:43 Done.
27 */
28 T visitTypeDecl(TypeDecl type) => type.accept(this);
29 }
30
31 /**
32 * API visitor that visits the entire API hierarchically by default.
33 */
34 class HierarchicalApiVisitor extends ApiVisitor {
35 /**
36 * The API to visit.
37 */
38 final Api api;
39
40 HierarchicalApiVisitor(this.api);
41
42 void visitApi() {
43 api.domains.forEach(visitDomain);
44 visitTypes(api.types);
45 visitRefactorings(api.refactorings);
46 }
47
48 void visitRefactorings(Refactorings refactorings) {
49 refactorings.forEach(visitRefactoring);
50 }
51
52 void visitRefactoring(Refactoring refactoring) {
53 if (refactoring.feedback != null) {
54 visitTypeDecl(refactoring.feedback);
55 }
56 if (refactoring.options != null) {
57 visitTypeDecl(refactoring.options);
58 }
59 }
60
61 void visitTypes(Types types) {
62 types.forEach(visitTypeDefinition);
63 }
64
65 void visitDomain(Domain domain) {
66 domain.requests.forEach(visitRequest);
67 domain.notifications.forEach(visitNotification);
68 }
69
70 void visitNotification(Notification notification) {
71 if (notification.params != null) {
72 visitTypeDecl(notification.params);
73 }
74 }
75
76 void visitRequest(Request request) {
77 if (request.params != null) {
78 visitTypeDecl(request.params);
79 }
80 if (request.result != null) {
81 visitTypeDecl(request.result);
82 }
83 }
84
85 void visitTypeDefinition(TypeDefinition typeDefinition) {
86 visitTypeDecl(typeDefinition.type);
87 }
88
89 @override
90 void visitTypeEnum(TypeEnum typeEnum) {
91 typeEnum.values.forEach(visitTypeEnumValue);
92 }
93
94 void visitTypeEnumValue(TypeEnumValue typeEnumValue) {
95 }
96
97 @override
98 void visitTypeList(TypeList typeList) {
99 visitTypeDecl(typeList.itemType);
100 }
101
102 @override
103 void visitTypeMap(TypeMap typeMap) {
104 visitTypeDecl(typeMap.keyType);
105 visitTypeDecl(typeMap.valueType);
106 }
107
108 @override
109 void visitTypeObject(TypeObject typeObject) {
110 typeObject.fields.forEach(visitTypeObjectField);
111 }
112
113 void visitTypeObjectField(TypeObjectField typeObjectField) {
114 visitTypeDecl(typeObjectField.type);
115 }
116
117 @override
118 void visitTypeReference(TypeReference typeReference) {
119 }
120
121 /**
122 * If [type] is a [TypeReference] which points to another [TypeReference],
123 * follow the chain until the last [TypeReference] is reached.
124 */
125 TypeReference resolveTypeReferenceChain(TypeReference type) {
126 while (api.types.containsKey(type.typeName)) {
127 TypeDecl referredType = api.types[type.typeName].type;
128 if (referredType is TypeReference) {
129 type = referredType;
130 continue;
131 }
132 break;
133 }
134 return type;
135 }
136 }
137
138 /**
139 * Base class for objects in the API model
scheglov 2014/08/06 18:20:39 .
Paul Berry 2014/08/06 18:32:43 Done.
140 */
141 class ApiNode {
142 /**
143 * Html element representing this part of the API.
144 */
145 final dom.Element html;
146
147 ApiNode(this.html);
148 }
149
150 /**
151 * Toplevel container for the API.
152 */
153 class Api extends ApiNode {
154 final String version;
155 final List<Domain> domains;
156 final Types types;
157 final Refactorings refactorings;
158
159 Api(this.version, this.domains, this.types, this.refactorings, dom.Element
160 html) : super(html);
161 }
162
163 /**
164 * A collection of refactoring definitions.
165 */
166 class Refactorings extends ApiNode with IterableMixin<Refactoring> {
167 final List<Refactoring> refactorings;
168
169 Refactorings(this.refactorings, dom.Element html) : super(html);
170
171 @override
172 Iterator<Refactoring> get iterator => refactorings.iterator;
173 }
174
175 /**
176 * Description of a single refactoring.
177 */
178 class Refactoring extends ApiNode {
179 /**
180 * Name of the refactoring. This should match one of the values allowed for
181 * RefactoringKind.
182 */
183 final String kind;
184
185 /**
186 * Type of the refactoring feedback, or null if the refactoring has no
187 * feedback.
188 */
189 final TypeObject feedback;
190
191 /**
192 * Type of the refactoring options, or null if the refactoring has no options.
193 */
194 final TypeObject options;
195
196 Refactoring(this.kind, this.feedback, this.options, dom.Element html) : super(
197 html);
198 }
199
200 /**
201 * A collection of type definitions.
202 */
203 class Types extends ApiNode with IterableMixin<TypeDefinition> {
204 final Map<String, TypeDefinition> types;
205
206 Types(this.types, dom.Element html) : super(html);
207
208 bool containsKey(String typeName) => types.containsKey(typeName);
209
210 @override
211 Iterator<TypeDefinition> get iterator => types.values.iterator;
212
213 TypeDefinition operator [](String typeName) => types[typeName];
214
215 Iterable<String> get keys => types.keys;
216 }
217
218 /**
219 * Definition of a single domain.
220 */
221 class Domain extends ApiNode {
222 final String name;
223 final List<Request> requests;
224 final List<Notification> notifications;
225
226 Domain(this.name, this.requests, this.notifications, dom.Element html) :
227 super(html);
228 }
229
230 /**
231 * Description of a request method.
232 */
233 class Request extends ApiNode {
234 /**
235 * Name of the domain enclosing this request.
236 */
237 final String domainName;
238
239 /**
240 * Name of the request, without the domain prefix.
241 */
242 final String method;
243
244 /**
245 * Type of the object associated with the "params" key in the request object,
246 * or null if the request has no parameters.
247 */
248 final TypeObject params;
249
250 /**
251 * Type of the object associated with the "result" key in the response object,
252 * or null if the response has no results.
253 */
254 final TypeObject result;
255
256 Request(this.domainName, this.method, this.params, this.result, dom.Element
257 html) : super(html);
258
259 /**
260 * Get the name of the request, including the domain prefix.
261 */
262 String get longMethod => '$domainName.$method';
263
264 /**
265 * Get the full type of the request object, including the common "id" and
266 * "method" fields.
267 */
268 TypeDecl get requestType {
269 List<TypeObjectField> fields = [new TypeObjectField('id', new TypeReference(
270 'String', null), null), new TypeObjectField('method', new TypeReference(
271 'String', null), null, value: '$domainName.$method')];
272 if (params != null) {
273 fields.add(new TypeObjectField('params', params, null));
274 }
275 return new TypeObject(fields, null);
276 }
277
278 /**
279 * Get the full type of the response object, including the common "id" and
280 * "error" fields.
281 */
282 TypeDecl get responseType {
283 List<TypeObjectField> fields = [new TypeObjectField('id', new TypeReference(
284 'String', null), null), new TypeObjectField('error', new TypeReference(' Error',
285 null), null, optional: true)];
286 if (result != null) {
287 fields.add(new TypeObjectField('result', result, null));
288 }
289 return new TypeObject(fields, null);
290 }
291 }
292
293 /**
294 * Description of a request method.
295 */
296 class Notification extends ApiNode {
297 /**
298 * Name of the domain enclosing this request.
299 */
300 final String domainName;
301
302 /**
303 * Name of the notification, without the domain prefix.
304 */
305 final String event;
306
307 /**
308 * Type of the object associated with the "params" key in the notification
309 * object, or null if the notification has no parameters.
310 */
311 final TypeObject params;
312
313 Notification(this.domainName, this.event, this.params, dom.Element html) :
314 super(html);
315
316 /**
317 * Get the name of the notification, including the domain prefix.
318 */
319 String get longEvent => '$domainName.$event';
320
321 /**
322 * Get the full type of the notification object, including the common "id"
323 * and "error" fields.
324 */
325 TypeDecl get notificationType {
326 List<TypeObjectField> fields = [new TypeObjectField('event',
327 new TypeReference('String', null), null, value: '$domainName.$event')];
328 if (params != null) {
329 fields.add(new TypeObjectField('params', params, null));
330 }
331 return new TypeObject(fields, null);
332 }
333 }
334
335 /**
336 * Description of a named type definition.
337 */
338 class TypeDefinition extends ApiNode {
339 final String name;
340 final TypeDecl type;
341
342 TypeDefinition(this.name, this.type, dom.Element html) : super(html);
343 }
344
345 /**
346 * Base class for all possible types.
347 */
348 abstract class TypeDecl extends ApiNode {
349 TypeDecl(dom.Element html) : super(html);
350
351 accept(ApiVisitor visitor);
352 }
353
354 /**
355 * A reference to a type which is either defined elsewhere in the API or which
356 * is built-in ([String], [bool], or [int]).
357 */
358 class TypeReference extends TypeDecl {
359 final String typeName;
360
361 TypeReference(this.typeName, dom.Element html) : super(html) {
362 if (typeName.isEmpty) {
363 throw new Exception('Empty type name');
364 }
365 }
366
367 accept(ApiVisitor visitor) => visitor.visitTypeReference(this);
368 }
369
370 /**
371 * Type of a JSON object with specified fields, some of which may be optional.
372 */
373 class TypeObject extends TypeDecl {
374 final List<TypeObjectField> fields;
375
376 TypeObject(this.fields, dom.Element html) : super(html);
377
378 accept(ApiVisitor visitor) => visitor.visitTypeObject(this);
379 }
380
381 /**
382 * Description of a single field in a [TypeObject].
383 */
384 class TypeObjectField extends ApiNode {
385 final String name;
386 final TypeDecl type;
387 final bool optional;
388
389 /**
390 * Value which the field is required to contain, or null if it may vary.
391 */
392 final Object value;
393
394 TypeObjectField(this.name, this.type, dom.Element html, {this.optional:
395 false, this.value}) : super(html);
396 }
397
398 /**
399 * Type of a JSON list.
400 */
401 class TypeList extends TypeDecl {
402 final TypeDecl itemType;
403
404 TypeList(this.itemType, dom.Element html) : super(html);
405
406 accept(ApiVisitor visitor) => visitor.visitTypeList(this);
407 }
408
409 /**
410 * Type of a JSON map.
411 */
412 class TypeMap extends TypeDecl {
413 /**
414 * Type of map keys. Note that since JSON map keys must always be strings,
415 * this must either be a [TypeReference] for [String], or a [TypeReference]
416 * to a type which is defined in the API as an enum or a synonym for [String].
417 */
418 final TypeReference keyType;
419
420 /**
421 * Type of map values.
422 */
423 final TypeDecl valueType;
424
425 TypeMap(this.keyType, this.valueType, dom.Element html) : super(html);
426
427 accept(ApiVisitor visitor) => visitor.visitTypeMap(this);
428 }
429
430 /**
431 * Type of an enum. We represent enums in JSON as strings, so this type
432 * declaration simply lists the allowed values.
433 */
434 class TypeEnum extends TypeDecl {
435 final List<TypeEnumValue> values;
436
437 TypeEnum(this.values, dom.Element html) : super(html);
438
439 accept(ApiVisitor visitor) => visitor.visitTypeEnum(this);
440 }
441
442 /**
443 * Description of a single allowed value for an enum.
444 */
445 class TypeEnumValue extends ApiNode {
446 final String value;
447
448 TypeEnumValue(this.value, dom.Element html) : super(html);
449 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698