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