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 library protocol; | 5 library protocol; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 | 9 |
10 part 'generated_protocol.dart'; | 10 part 'generated_protocol.dart'; |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 * Retrieve the RefactoringKind that should be assumed when decoding | 274 * Retrieve the RefactoringKind that should be assumed when decoding |
275 * refactoring feedback objects, or null if no refactoring feedback object is | 275 * refactoring feedback objects, or null if no refactoring feedback object is |
276 * expected to be encountered. | 276 * expected to be encountered. |
277 */ | 277 */ |
278 RefactoringKind get refactoringKind; | 278 RefactoringKind get refactoringKind; |
279 | 279 |
280 /** | 280 /** |
281 * Create an exception to throw if the JSON object at [jsonPath] fails to | 281 * Create an exception to throw if the JSON object at [jsonPath] fails to |
282 * match the API definition of [expected]. | 282 * match the API definition of [expected]. |
283 */ | 283 */ |
284 dynamic mismatch(String jsonPath, String expected); | 284 dynamic mismatch(String jsonPath, String expected, [Object actual]); |
285 | 285 |
286 /** | 286 /** |
287 * Create an exception to throw if the JSON object at [jsonPath] is missing | 287 * Create an exception to throw if the JSON object at [jsonPath] is missing |
288 * the key [key]. | 288 * the key [key]. |
289 */ | 289 */ |
290 dynamic missingKey(String jsonPath, String key); | 290 dynamic missingKey(String jsonPath, String key); |
291 | 291 |
292 /** | 292 /** |
293 * Decode a JSON object that is expected to be a boolean. The strings "true" | 293 * Decode a JSON object that is expected to be a boolean. The strings "true" |
294 * and "false" are also accepted. | 294 * and "false" are also accepted. |
295 */ | 295 */ |
296 bool _decodeBool(String jsonPath, Object json) { | 296 bool _decodeBool(String jsonPath, Object json) { |
297 if (json is bool) { | 297 if (json is bool) { |
298 return json; | 298 return json; |
299 } else if (json == 'true') { | 299 } else if (json == 'true') { |
300 return true; | 300 return true; |
301 } else if (json == 'false') { | 301 } else if (json == 'false') { |
302 return false; | 302 return false; |
303 } | 303 } |
304 throw mismatch(jsonPath, 'bool'); | 304 throw mismatch(jsonPath, 'bool', json); |
305 } | 305 } |
306 | 306 |
307 /** | 307 /** |
308 * Decode a JSON object that is expected to be an integer. A string | 308 * Decode a JSON object that is expected to be an integer. A string |
309 * representation of an integer is also accepted. | 309 * representation of an integer is also accepted. |
310 */ | 310 */ |
311 int _decodeInt(String jsonPath, Object json) { | 311 int _decodeInt(String jsonPath, Object json) { |
312 if (json is int) { | 312 if (json is int) { |
313 return json; | 313 return json; |
314 } else if (json is String) { | 314 } else if (json is String) { |
315 return int.parse(json, onError: (String value) { | 315 return int.parse(json, onError: (String value) { |
316 throw mismatch(jsonPath, 'int'); | 316 throw mismatch(jsonPath, 'int', json); |
317 }); | 317 }); |
318 } | 318 } |
319 throw mismatch(jsonPath, 'int'); | 319 throw mismatch(jsonPath, 'int', json); |
320 } | 320 } |
321 | 321 |
322 /** | 322 /** |
323 * Decode a JSON object that is expected to be a List. [decoder] is used to | 323 * Decode a JSON object that is expected to be a List. [decoder] is used to |
324 * decode the items in the list. | 324 * decode the items in the list. |
325 */ | 325 */ |
326 List _decodeList(String jsonPath, Object json, | 326 List _decodeList(String jsonPath, Object json, |
327 [JsonDecoderCallback decoder]) { | 327 [JsonDecoderCallback decoder]) { |
328 if (json == null) { | 328 if (json == null) { |
329 return []; | 329 return []; |
330 } else if (json is List) { | 330 } else if (json is List) { |
331 List result = []; | 331 List result = []; |
332 for (int i = 0; i < json.length; i++) { | 332 for (int i = 0; i < json.length; i++) { |
333 result.add(decoder('$jsonPath[$i]', json[i])); | 333 result.add(decoder('$jsonPath[$i]', json[i])); |
334 } | 334 } |
335 return result; | 335 return result; |
336 } else { | 336 } else { |
337 throw mismatch(jsonPath, 'List'); | 337 throw mismatch(jsonPath, 'List', json); |
338 } | 338 } |
339 } | 339 } |
340 | 340 |
341 /** | 341 /** |
342 * Decode a JSON object that is expected to be a Map. [keyDecoder] is used | 342 * Decode a JSON object that is expected to be a Map. [keyDecoder] is used |
343 * to decode the keys, and [valueDecoder] is used to decode the values. | 343 * to decode the keys, and [valueDecoder] is used to decode the values. |
344 */ | 344 */ |
345 Map _decodeMap(String jsonPath, Object json, | 345 Map _decodeMap(String jsonPath, Object json, |
346 {JsonDecoderCallback keyDecoder, JsonDecoderCallback valueDecoder}) { | 346 {JsonDecoderCallback keyDecoder, JsonDecoderCallback valueDecoder}) { |
347 if (json == null) { | 347 if (json == null) { |
348 return {}; | 348 return {}; |
349 } else if (json is Map) { | 349 } else if (json is Map) { |
350 Map result = {}; | 350 Map result = {}; |
351 json.forEach((String key, value) { | 351 json.forEach((String key, value) { |
352 Object decodedKey; | 352 Object decodedKey; |
353 if (keyDecoder != null) { | 353 if (keyDecoder != null) { |
354 decodedKey = keyDecoder('$jsonPath.key', key); | 354 decodedKey = keyDecoder('$jsonPath.key', key); |
355 } else { | 355 } else { |
356 decodedKey = key; | 356 decodedKey = key; |
357 } | 357 } |
358 if (valueDecoder != null) { | 358 if (valueDecoder != null) { |
359 value = valueDecoder('$jsonPath[${JSON.encode(key)}]', value); | 359 value = valueDecoder('$jsonPath[${JSON.encode(key)}]', value); |
360 } | 360 } |
361 result[decodedKey] = value; | 361 result[decodedKey] = value; |
362 }); | 362 }); |
363 return result; | 363 return result; |
364 } else { | 364 } else { |
365 throw mismatch(jsonPath, 'Map'); | 365 throw mismatch(jsonPath, 'Map', json); |
366 } | 366 } |
367 } | 367 } |
368 | 368 |
369 /** | 369 /** |
370 * Decode a JSON object that is expected to be a string. | 370 * Decode a JSON object that is expected to be a string. |
371 */ | 371 */ |
372 String _decodeString(String jsonPath, Object json) { | 372 String _decodeString(String jsonPath, Object json) { |
373 if (json is String) { | 373 if (json is String) { |
374 return json; | 374 return json; |
375 } else { | 375 } else { |
376 throw mismatch(jsonPath, 'String'); | 376 throw mismatch(jsonPath, 'String', json); |
377 } | 377 } |
378 } | 378 } |
379 | 379 |
380 /** | 380 /** |
381 * Decode a JSON object that is expected to be one of several choices, | 381 * Decode a JSON object that is expected to be one of several choices, |
382 * where the choices are disambiguated by the contents of the field [field]. | 382 * where the choices are disambiguated by the contents of the field [field]. |
383 * [decoders] is a map from each possible string in the field to the decoder | 383 * [decoders] is a map from each possible string in the field to the decoder |
384 * that should be used to decode the JSON object. | 384 * that should be used to decode the JSON object. |
385 */ | 385 */ |
386 Object _decodeUnion(String jsonPath, Map json, String field, | 386 Object _decodeUnion(String jsonPath, Map json, String field, |
387 Map<String, JsonDecoderCallback> decoders) { | 387 Map<String, JsonDecoderCallback> decoders) { |
388 if (json is Map) { | 388 if (json is Map) { |
389 if (!json.containsKey(field)) { | 389 if (!json.containsKey(field)) { |
390 throw missingKey(jsonPath, field); | 390 throw missingKey(jsonPath, field); |
391 } | 391 } |
392 var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]'; | 392 var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]'; |
393 String disambiguator = _decodeString(disambiguatorPath, json[field]); | 393 String disambiguator = _decodeString(disambiguatorPath, json[field]); |
394 if (!decoders.containsKey(disambiguator)) { | 394 if (!decoders.containsKey(disambiguator)) { |
395 throw mismatch(disambiguatorPath, 'One of: ${decoders.keys.toList()}'); | 395 throw mismatch(disambiguatorPath, 'One of: ${decoders.keys.toList()}', j
son); |
396 } | 396 } |
397 return decoders[disambiguator](jsonPath, json); | 397 return decoders[disambiguator](jsonPath, json); |
398 } else { | 398 } else { |
399 throw mismatch(jsonPath, 'Map'); | 399 throw mismatch(jsonPath, 'Map', json); |
400 } | 400 } |
401 } | 401 } |
402 } | 402 } |
403 | 403 |
404 /** | 404 /** |
405 * Instances of the class [Notification] represent a notification from the | 405 * Instances of the class [Notification] represent a notification from the |
406 * server about an event that occurred. | 406 * server about an event that occurred. |
407 */ | 407 */ |
408 class Notification { | 408 class Notification { |
409 /** | 409 /** |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 final Request _request; | 609 final Request _request; |
610 | 610 |
611 RequestDecoder(this._request); | 611 RequestDecoder(this._request); |
612 | 612 |
613 RefactoringKind get refactoringKind { | 613 RefactoringKind get refactoringKind { |
614 // Refactoring feedback objects should never appear in requests. | 614 // Refactoring feedback objects should never appear in requests. |
615 return null; | 615 return null; |
616 } | 616 } |
617 | 617 |
618 @override | 618 @override |
619 dynamic mismatch(String jsonPath, String expected) { | 619 dynamic mismatch(String jsonPath, String expected, [Object actual]) { |
| 620 StringBuffer buffer = new StringBuffer(); |
| 621 buffer.write('Expected to be '); |
| 622 buffer.write(expected); |
| 623 if (actual != null) { |
| 624 buffer.write('; found "'); |
| 625 buffer.write(JSON.encode(actual)); |
| 626 buffer.write('"'); |
| 627 } |
620 return new RequestFailure(new Response.invalidParameter( | 628 return new RequestFailure(new Response.invalidParameter( |
621 _request, jsonPath, 'Expected to be $expected')); | 629 _request, jsonPath, buffer.toString())); |
622 } | 630 } |
623 | 631 |
624 @override | 632 @override |
625 dynamic missingKey(String jsonPath, String key) { | 633 dynamic missingKey(String jsonPath, String key) { |
626 return new RequestFailure(new Response.invalidParameter( | 634 return new RequestFailure(new Response.invalidParameter( |
627 _request, jsonPath, 'Expected to contain key ${JSON.encode(key)}')); | 635 _request, jsonPath, 'Expected to contain key ${JSON.encode(key)}')); |
628 } | 636 } |
629 } | 637 } |
630 | 638 |
631 /** | 639 /** |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 /** | 916 /** |
909 * JsonDecoder for decoding responses from the server. This is intended to be | 917 * JsonDecoder for decoding responses from the server. This is intended to be |
910 * used only for testing. Errors are reported using bare [Exception] objects. | 918 * used only for testing. Errors are reported using bare [Exception] objects. |
911 */ | 919 */ |
912 class ResponseDecoder extends JsonDecoder { | 920 class ResponseDecoder extends JsonDecoder { |
913 final RefactoringKind refactoringKind; | 921 final RefactoringKind refactoringKind; |
914 | 922 |
915 ResponseDecoder(this.refactoringKind); | 923 ResponseDecoder(this.refactoringKind); |
916 | 924 |
917 @override | 925 @override |
918 dynamic mismatch(String jsonPath, String expected) { | 926 dynamic mismatch(String jsonPath, String expected, [Object actual]) { |
919 return new Exception('Expected $expected at $jsonPath'); | 927 StringBuffer buffer = new StringBuffer(); |
| 928 buffer.write('Expected '); |
| 929 buffer.write(expected); |
| 930 if (actual != null) { |
| 931 buffer.write(' found "'); |
| 932 buffer.write(JSON.encode(actual)); |
| 933 buffer.write('"'); |
| 934 } |
| 935 buffer.write(' at '); |
| 936 buffer.write(jsonPath); |
| 937 return new Exception(buffer.toString()); |
920 } | 938 } |
921 | 939 |
922 @override | 940 @override |
923 dynamic missingKey(String jsonPath, String key) { | 941 dynamic missingKey(String jsonPath, String key) { |
924 return new Exception('Missing key $key at $jsonPath'); | 942 return new Exception('Missing key $key at $jsonPath'); |
925 } | 943 } |
926 } | 944 } |
927 | 945 |
928 /** | 946 /** |
929 * Jenkins hash function, optimized for small integers. Borrowed from | 947 * Jenkins hash function, optimized for small integers. Borrowed from |
(...skipping 12 matching lines...) Expand all Loading... |
942 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); | 960 hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); |
943 hash = hash ^ (hash >> 11); | 961 hash = hash ^ (hash >> 11); |
944 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); | 962 return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); |
945 } | 963 } |
946 | 964 |
947 static int hash2(a, b) => finish(combine(combine(0, a), b)); | 965 static int hash2(a, b) => finish(combine(combine(0, a), b)); |
948 | 966 |
949 static int hash4(a, b, c, d) => | 967 static int hash4(a, b, c, d) => |
950 finish(combine(combine(combine(combine(0, a), b), c), d)); | 968 finish(combine(combine(combine(combine(0, a), b), c), d)); |
951 } | 969 } |
OLD | NEW |