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

Side by Side Diff: pkg/analyzer_plugin/tool/spec/api.dart

Issue 2664213003: Add the generator and the generated files (Closed)
Patch Set: add missed files Created 3 years, 10 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
OLDNEW
(Empty)
1 // Copyright (c) 2017, 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 import 'dart:collection';
10
11 import 'package:html/dom.dart' as dom;
12
13 /**
14 * Toplevel container for the API.
15 */
16 class Api extends ApiNode {
17 final String version;
18 final List<Domain> domains;
19 final Types types;
20 final Refactorings refactorings;
21
22 Api(this.version, this.domains, this.types, this.refactorings,
23 dom.Element html,
24 {bool experimental})
25 : super(html, experimental);
26 }
27
28 /**
29 * Base class for objects in the API model.
30 */
31 class ApiNode {
32 /**
33 * A flag to indicate if this API is experimental.
34 */
35 final bool experimental;
36
37 /**
38 * Html element representing this part of the API.
39 */
40 final dom.Element html;
41
42 ApiNode(this.html, bool experimental)
43 : this.experimental = experimental ?? false;
44 }
45
46 /**
47 * Base class for visiting the API definition.
48 */
49 abstract class ApiVisitor<T> {
50 /**
51 * Dispatch the given [type] to the visitor.
52 */
53 T visitTypeDecl(TypeDecl type) => type.accept(this) as T;
54 T visitTypeEnum(TypeEnum typeEnum);
55 T visitTypeList(TypeList typeList);
56 T visitTypeMap(TypeMap typeMap);
57 T visitTypeObject(TypeObject typeObject);
58 T visitTypeReference(TypeReference typeReference);
59
60 T visitTypeUnion(TypeUnion typeUnion);
61 }
62
63 /**
64 * Definition of a single domain.
65 */
66 class Domain extends ApiNode {
67 final String name;
68 final List<Request> requests;
69 final List<Notification> notifications;
70
71 Domain(this.name, this.requests, this.notifications, dom.Element html,
72 {bool experimental})
73 : super(html, experimental);
74 }
75
76 /**
77 * API visitor that visits the entire API hierarchically by default.
78 */
79 class HierarchicalApiVisitor extends ApiVisitor {
80 /**
81 * The API to visit.
82 */
83 final Api api;
84
85 HierarchicalApiVisitor(this.api);
86
87 /**
88 * If [type] is a [TypeReference] that is defined in the API, follow the
89 * chain until a non-[TypeReference] is found, if possible.
90 *
91 * If it is not possible (because the chain ends with a [TypeReference] that
92 * is not defined in the API), then that final [TypeReference] is returned.
93 */
94 TypeDecl resolveTypeReferenceChain(TypeDecl type) {
95 while (type is TypeReference && api.types.containsKey(type.typeName)) {
96 type = api.types[(type as TypeReference).typeName].type;
97 }
98 return type;
99 }
100
101 void visitApi() {
102 api.domains.forEach(visitDomain);
103 visitTypes(api.types);
104 visitRefactorings(api.refactorings);
105 }
106
107 void visitDomain(Domain domain) {
108 domain.requests.forEach(visitRequest);
109 domain.notifications.forEach(visitNotification);
110 }
111
112 void visitNotification(Notification notification) {
113 if (notification.params != null) {
114 visitTypeDecl(notification.params);
115 }
116 }
117
118 void visitRefactoring(Refactoring refactoring) {
119 if (refactoring.feedback != null) {
120 visitTypeDecl(refactoring.feedback);
121 }
122 if (refactoring.options != null) {
123 visitTypeDecl(refactoring.options);
124 }
125 }
126
127 void visitRefactorings(Refactorings refactorings) {
128 refactorings?.forEach(visitRefactoring);
129 }
130
131 void visitRequest(Request request) {
132 if (request.params != null) {
133 visitTypeDecl(request.params);
134 }
135 if (request.result != null) {
136 visitTypeDecl(request.result);
137 }
138 }
139
140 void visitTypeDefinition(TypeDefinition typeDefinition) {
141 visitTypeDecl(typeDefinition.type);
142 }
143
144 @override
145 void visitTypeEnum(TypeEnum typeEnum) {
146 typeEnum.values.forEach(visitTypeEnumValue);
147 }
148
149 void visitTypeEnumValue(TypeEnumValue typeEnumValue) {}
150
151 @override
152 void visitTypeList(TypeList typeList) {
153 visitTypeDecl(typeList.itemType);
154 }
155
156 @override
157 void visitTypeMap(TypeMap typeMap) {
158 visitTypeDecl(typeMap.keyType);
159 visitTypeDecl(typeMap.valueType);
160 }
161
162 @override
163 void visitTypeObject(TypeObject typeObject) {
164 typeObject.fields.forEach(visitTypeObjectField);
165 }
166
167 void visitTypeObjectField(TypeObjectField typeObjectField) {
168 visitTypeDecl(typeObjectField.type);
169 }
170
171 @override
172 void visitTypeReference(TypeReference typeReference) {}
173
174 void visitTypes(Types types) {
175 types.forEach(visitTypeDefinition);
176 }
177
178 @override
179 void visitTypeUnion(TypeUnion typeUnion) {
180 typeUnion.choices.forEach(visitTypeDecl);
181 }
182 }
183
184 /**
185 * Description of a notification method.
186 */
187 class Notification extends ApiNode {
188 /**
189 * Name of the domain enclosing this request.
190 */
191 final String domainName;
192
193 /**
194 * Name of the notification, without the domain prefix.
195 */
196 final String event;
197
198 /**
199 * Type of the object associated with the "params" key in the notification
200 * object, or null if the notification has no parameters.
201 */
202 final TypeObject params;
203
204 Notification(this.domainName, this.event, this.params, dom.Element html,
205 {bool experimental})
206 : super(html, experimental);
207
208 /**
209 * Get the name of the notification, including the domain prefix.
210 */
211 String get longEvent => '$domainName.$event';
212
213 /**
214 * Get the full type of the notification object, including the common "id"
215 * and "error" fields.
216 */
217 TypeDecl get notificationType {
218 List<TypeObjectField> fields = [
219 new TypeObjectField('event', new TypeReference('String', null), null,
220 value: '$domainName.$event')
221 ];
222 if (params != null) {
223 fields.add(new TypeObjectField('params', params, null));
224 }
225 return new TypeObject(fields, null);
226 }
227 }
228
229 /**
230 * Description of a single refactoring.
231 */
232 class Refactoring extends ApiNode {
233 /**
234 * Name of the refactoring. This should match one of the values allowed for
235 * RefactoringKind.
236 */
237 final String kind;
238
239 /**
240 * Type of the refactoring feedback, or null if the refactoring has no
241 * feedback.
242 */
243 final TypeObject feedback;
244
245 /**
246 * Type of the refactoring options, or null if the refactoring has no options.
247 */
248 final TypeObject options;
249
250 Refactoring(this.kind, this.feedback, this.options, dom.Element html,
251 {bool experimental})
252 : super(html, experimental);
253 }
254
255 /**
256 * A collection of refactoring definitions.
257 */
258 class Refactorings extends ApiNode with IterableMixin<Refactoring> {
259 final List<Refactoring> refactorings;
260
261 Refactorings(this.refactorings, dom.Element html, {bool experimental})
262 : super(html, experimental);
263
264 @override
265 Iterator<Refactoring> get iterator => refactorings.iterator;
266 }
267
268 /**
269 * Description of a request method.
270 */
271 class Request extends ApiNode {
272 /**
273 * Name of the domain enclosing this request.
274 */
275 final String domainName;
276
277 /**
278 * Name of the request, without the domain prefix.
279 */
280 final String method;
281
282 /**
283 * Type of the object associated with the "params" key in the request object,
284 * or null if the request has no parameters.
285 */
286 final TypeObject params;
287
288 /**
289 * Type of the object associated with the "result" key in the response object,
290 * or null if the response has no results.
291 */
292 final TypeObject result;
293
294 Request(
295 this.domainName, this.method, this.params, this.result, dom.Element html,
296 {bool experimental})
297 : super(html, experimental);
298
299 /**
300 * Get the name of the request, including the domain prefix.
301 */
302 String get longMethod => '$domainName.$method';
303
304 /**
305 * Get the full type of the request object, including the common "id" and
306 * "method" fields.
307 */
308 TypeDecl get requestType {
309 List<TypeObjectField> fields = [
310 new TypeObjectField('id', new TypeReference('String', null), null),
311 new TypeObjectField('method', new TypeReference('String', null), null,
312 value: '$domainName.$method')
313 ];
314 if (params != null) {
315 fields.add(new TypeObjectField('params', params, null));
316 }
317 return new TypeObject(fields, null);
318 }
319
320 /**
321 * Get the full type of the response object, including the common "id" and
322 * "error" fields.
323 */
324 TypeDecl get responseType {
325 List<TypeObjectField> fields = [
326 new TypeObjectField('id', new TypeReference('String', null), null),
327 new TypeObjectField(
328 'error', new TypeReference('RequestError', null), null,
329 optional: true)
330 ];
331 if (result != null) {
332 fields.add(new TypeObjectField('result', result, null));
333 }
334 return new TypeObject(fields, null);
335 }
336 }
337
338 /**
339 * Base class for all possible types.
340 */
341 abstract class TypeDecl extends ApiNode {
342 TypeDecl(dom.Element html, bool experimental) : super(html, experimental);
343
344 accept(ApiVisitor visitor);
345 }
346
347 /**
348 * Description of a named type definition.
349 */
350 class TypeDefinition extends ApiNode {
351 final String name;
352 final TypeDecl type;
353
354 TypeDefinition(this.name, this.type, dom.Element html, {bool experimental})
355 : super(html, experimental);
356 }
357
358 /**
359 * Type of an enum. We represent enums in JSON as strings, so this type
360 * declaration simply lists the allowed values.
361 */
362 class TypeEnum extends TypeDecl {
363 final List<TypeEnumValue> values;
364
365 TypeEnum(this.values, dom.Element html, {bool experimental})
366 : super(html, experimental);
367
368 @override
369 accept(ApiVisitor visitor) => visitor.visitTypeEnum(this);
370 }
371
372 /**
373 * Description of a single allowed value for an enum.
374 */
375 class TypeEnumValue extends ApiNode {
376 final String value;
377
378 TypeEnumValue(this.value, dom.Element html, {bool experimental})
379 : super(html, experimental);
380 }
381
382 /**
383 * Type of a JSON list.
384 */
385 class TypeList extends TypeDecl {
386 final TypeDecl itemType;
387
388 TypeList(this.itemType, dom.Element html, {bool experimental})
389 : super(html, experimental);
390
391 @override
392 accept(ApiVisitor visitor) => visitor.visitTypeList(this);
393 }
394
395 /**
396 * Type of a JSON map.
397 */
398 class TypeMap extends TypeDecl {
399 /**
400 * Type of map keys. Note that since JSON map keys must always be strings,
401 * this must either be a [TypeReference] for [String], or a [TypeReference]
402 * to a type which is defined in the API as an enum or a synonym for [String].
403 */
404 final TypeReference keyType;
405
406 /**
407 * Type of map values.
408 */
409 final TypeDecl valueType;
410
411 TypeMap(this.keyType, this.valueType, dom.Element html, {bool experimental})
412 : super(html, experimental);
413
414 @override
415 accept(ApiVisitor visitor) => visitor.visitTypeMap(this);
416 }
417
418 /**
419 * Type of a JSON object with specified fields, some of which may be optional.
420 */
421 class TypeObject extends TypeDecl {
422 final List<TypeObjectField> fields;
423
424 TypeObject(this.fields, dom.Element html, {bool experimental})
425 : super(html, experimental);
426
427 @override
428 accept(ApiVisitor visitor) => visitor.visitTypeObject(this);
429
430 /**
431 * Return the field with the given [name], or null if there is no such field.
432 */
433 TypeObjectField getField(String name) {
434 for (TypeObjectField field in fields) {
435 if (field.name == name) {
436 return field;
437 }
438 }
439 return null;
440 }
441 }
442
443 /**
444 * Description of a single field in a [TypeObject].
445 */
446 class TypeObjectField extends ApiNode {
447 final String name;
448 final TypeDecl type;
449 final bool optional;
450
451 /**
452 * Value that the field is required to contain, or null if it may vary.
453 */
454 final Object value;
455
456 TypeObjectField(this.name, this.type, dom.Element html,
457 {this.optional: false, this.value, bool experimental})
458 : super(html, experimental);
459 }
460
461 /**
462 * A reference to a type which is either defined elsewhere in the API or which
463 * is built-in ([String], [bool], or [int]).
464 */
465 class TypeReference extends TypeDecl {
466 final String typeName;
467
468 TypeReference(this.typeName, dom.Element html, {bool experimental})
469 : super(html, experimental) {
470 if (typeName.isEmpty) {
471 throw new Exception('Empty type name');
472 }
473 }
474
475 @override
476 accept(ApiVisitor visitor) => visitor.visitTypeReference(this);
477 }
478
479 /**
480 * A collection of type definitions.
481 */
482 class Types extends ApiNode with IterableMixin<TypeDefinition> {
483 final Map<String, TypeDefinition> types;
484
485 Types(this.types, dom.Element html, {bool experimental})
486 : super(html, experimental);
487
488 @override
489 Iterator<TypeDefinition> get iterator => types.values.iterator;
490
491 Iterable<String> get keys => types.keys;
492
493 TypeDefinition operator [](String typeName) => types[typeName];
494
495 bool containsKey(String typeName) => types.containsKey(typeName);
496 }
497
498 /**
499 * Type which represents a union among multiple choices.
500 */
501 class TypeUnion extends TypeDecl {
502 final List<TypeDecl> choices;
503
504 /**
505 * The field that is used to disambiguate this union
506 */
507 final String field;
508
509 TypeUnion(this.choices, this.field, dom.Element html, {bool experimental})
510 : super(html, experimental);
511
512 @override
513 accept(ApiVisitor visitor) => visitor.visitTypeUnion(this);
514 }
OLDNEW
« no previous file with comments | « pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart ('k') | pkg/analyzer_plugin/tool/spec/check_all_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698