| 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 |