OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dart._debugger; | 5 library dart._debugger; |
6 | 6 |
7 import 'dart:_foreign_helper' show JS; | 7 import 'dart:_foreign_helper' show JS; |
8 import 'dart:_runtime' as dart; | 8 import 'dart:_runtime' as dart; |
9 import 'dart:core'; | 9 import 'dart:core'; |
10 import 'dart:collection'; | 10 import 'dart:collection'; |
11 import 'dart:html' as html; | 11 import 'dart:html' as html; |
12 | 12 |
13 /// Config object to pass to devtools to signal that an object should not be | 13 /// JsonMLConfig object to pass to devtools to specify how an Object should |
14 /// formatted by the Dart formatter. This is used to specify that an Object | 14 /// be displayed. skipDart signals that an object should not be formatted |
| 15 /// by the Dart formatter. This is used to specify that an Object |
15 /// should just be displayed using the regular JavaScript view instead of a | 16 /// should just be displayed using the regular JavaScript view instead of a |
16 /// custom Dart view. For example, this is used to display the JavaScript view | 17 /// custom Dart view. For example, this is used to display the JavaScript view |
17 /// of a Dart Function as a child of the regular Function object. | 18 /// of a Dart Function as a child of the regular Function object. keyToString |
18 const skipDartConfig = const Object(); | 19 /// signals that a map key object should have its toString() displayed by |
| 20 /// the Dart formatter. |
| 21 /// |
| 22 /// We'd like this to be an enum, but we can't because it's a dev_compiler bug. |
| 23 class JsonMLConfig { |
| 24 const JsonMLConfig(this.name); |
| 25 |
| 26 final String name; |
| 27 static const none = const JsonMLConfig("none"); |
| 28 static const skipDart = const JsonMLConfig("skipDart"); |
| 29 static const keyToString = const JsonMLConfig("keyToString"); |
| 30 } |
| 31 |
19 final int maxIterableChildrenToDisplay = 50; | 32 final int maxIterableChildrenToDisplay = 50; |
20 | 33 |
21 var _devtoolsFormatter = new JsonMLFormatter(new DartFormatter()); | 34 var _devtoolsFormatter = new JsonMLFormatter(new DartFormatter()); |
22 | 35 |
23 String _typeof(object) => JS('String', 'typeof #', object); | 36 String _typeof(object) => JS('String', 'typeof #', object); |
24 | 37 |
25 List<String> getOwnPropertyNames(object) => JS('List<String>', | 38 List<String> getOwnPropertyNames(object) => JS('List<String>', |
26 'dart.list(Object.getOwnPropertyNames(#), #)', object, String); | 39 'dart.list(Object.getOwnPropertyNames(#), #)', object, String); |
27 | 40 |
28 List getOwnPropertySymbols(object) => | 41 List getOwnPropertySymbols(object) => |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 bool hasMethod(object, String name) { | 91 bool hasMethod(object, String name) { |
79 try { | 92 try { |
80 return dart.hasMethod(object, name); | 93 return dart.hasMethod(object, name); |
81 } catch (e) { | 94 } catch (e) { |
82 return false; | 95 return false; |
83 } | 96 } |
84 } | 97 } |
85 | 98 |
86 /// [JsonMLFormatter] consumes [NameValuePair] objects and | 99 /// [JsonMLFormatter] consumes [NameValuePair] objects and |
87 class NameValuePair { | 100 class NameValuePair { |
88 NameValuePair({this.name, this.value, bool skipDart}) | 101 NameValuePair({this.name, this.value, this.config: JsonMLConfig.none}); |
89 : skipDart = skipDart == true; | |
90 | 102 |
91 // Define equality and hashCode so that NameValuePair can be used | 103 // Define equality and hashCode so that NameValuePair can be used |
92 // in a Set to dedupe entries with duplicate names. | 104 // in a Set to dedupe entries with duplicate names. |
93 operator ==(other) => other is NameValuePair && other.name == name; | 105 operator ==(other) => other is NameValuePair && other.name == name; |
94 int get hashCode => name.hashCode; | 106 int get hashCode => name.hashCode; |
95 | 107 |
96 final String name; | 108 final String name; |
97 final Object value; | 109 final Object value; |
98 final bool skipDart; | 110 final JsonMLConfig config; |
99 } | 111 } |
100 | 112 |
101 class MapEntry { | 113 class MapEntry { |
102 MapEntry({this.key, this.value}); | 114 MapEntry({this.key, this.value}); |
103 | 115 |
104 final String key; | 116 final Object key; |
105 final Object value; | 117 final Object value; |
106 } | 118 } |
107 | 119 |
108 class ClassMetadata { | 120 class ClassMetadata { |
109 ClassMetadata(this.object); | 121 ClassMetadata(this.object); |
110 | 122 |
111 final Object object; | 123 final Object object; |
112 } | 124 } |
113 | 125 |
114 class HeritageClause { | 126 class HeritageClause { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 // TODO(jacobr): define a SimpleFormatter base class that DartFormatter | 198 // TODO(jacobr): define a SimpleFormatter base class that DartFormatter |
187 // implements if we decide to use this class elsewhere. We specify that the | 199 // implements if we decide to use this class elsewhere. We specify that the |
188 // type is DartFormatter here purely to get type checking benefits not because | 200 // type is DartFormatter here purely to get type checking benefits not because |
189 // this class is really intended to only support instances of type | 201 // this class is really intended to only support instances of type |
190 // DartFormatter. | 202 // DartFormatter. |
191 DartFormatter _simpleFormatter; | 203 DartFormatter _simpleFormatter; |
192 | 204 |
193 JsonMLFormatter(this._simpleFormatter); | 205 JsonMLFormatter(this._simpleFormatter); |
194 | 206 |
195 header(object, config) { | 207 header(object, config) { |
196 if (identical(config, skipDartConfig) || isNativeJavaScriptObject(object)) { | 208 if (config == JsonMLConfig.skipDart || isNativeJavaScriptObject(object)) { |
197 return null; | 209 return null; |
198 } | 210 } |
199 | 211 |
200 var c = _simpleFormatter.preview(object); | 212 var c = _simpleFormatter.preview(object); |
201 if (c == null) return null; | 213 if (c == null) return null; |
202 | 214 |
| 215 if (config == JsonMLConfig.keyToString) { |
| 216 c = object.toString(); |
| 217 } |
| 218 |
203 // Indicate this is a Dart Object by using a Dart background color. | 219 // Indicate this is a Dart Object by using a Dart background color. |
204 // This is stylistically a bit ugly but it eases distinguishing Dart and | 220 // This is stylistically a bit ugly but it eases distinguishing Dart and |
205 // JS objects. | 221 // JS objects. |
206 var element = new JsonMLElement('span') | 222 var element = new JsonMLElement('span') |
207 ..setStyle('background-color: #d9edf7') | 223 ..setStyle('background-color: #d9edf7') |
208 ..createTextChild(c); | 224 ..createTextChild(c); |
209 return element.toJsonML(); | 225 return element.toJsonML(); |
210 } | 226 } |
211 | 227 |
212 bool hasBody(object) => _simpleFormatter.hasChildren(object); | 228 bool hasBody(object) => _simpleFormatter.hasChildren(object); |
(...skipping 10 matching lines...) Expand all Loading... |
223 var li = body.createChild('li'); | 239 var li = body.createChild('li'); |
224 var nameSpan = new JsonMLElement('span') | 240 var nameSpan = new JsonMLElement('span') |
225 ..createTextChild(child.name != null ? child.name + ': ' : '') | 241 ..createTextChild(child.name != null ? child.name + ': ' : '') |
226 ..setStyle('color: rgb(136, 19, 145);'); | 242 ..setStyle('color: rgb(136, 19, 145);'); |
227 if (_typeof(child.value) == 'object' || | 243 if (_typeof(child.value) == 'object' || |
228 _typeof(child.value) == 'function') { | 244 _typeof(child.value) == 'function') { |
229 nameSpan.addStyle("padding-left: 13px;"); | 245 nameSpan.addStyle("padding-left: 13px;"); |
230 | 246 |
231 li.appendChild(nameSpan); | 247 li.appendChild(nameSpan); |
232 var objectTag = li.createObjectTag(child.value); | 248 var objectTag = li.createObjectTag(child.value); |
233 if (child.skipDart) { | 249 objectTag.addAttribute('config', child.config); |
234 objectTag.addAttribute('config', skipDartConfig); | |
235 } | |
236 if (!_simpleFormatter.hasChildren(child.value)) { | 250 if (!_simpleFormatter.hasChildren(child.value)) { |
237 li.setStyle("padding-left: 13px;"); | 251 li.setStyle("padding-left: 13px;"); |
238 } | 252 } |
239 } else { | 253 } else { |
240 li.setStyle("padding-left: 13px;"); | 254 li.setStyle("padding-left: 13px;"); |
241 li.createChild('span') | 255 li.createChild('span') |
242 ..appendChild(nameSpan) | 256 ..appendChild(nameSpan) |
243 ..createTextChild(safePreview(child.value)); | 257 ..createTextChild(safePreview(child.value)); |
244 } | 258 } |
245 } | 259 } |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 | 433 |
420 bool hasChildren(object) => true; | 434 bool hasChildren(object) => true; |
421 | 435 |
422 String preview(object) { | 436 String preview(object) { |
423 return dart.typeName(dart.getReifiedType(object)); | 437 return dart.typeName(dart.getReifiedType(object)); |
424 } | 438 } |
425 | 439 |
426 List<NameValuePair> children(object) => <NameValuePair>[ | 440 List<NameValuePair> children(object) => <NameValuePair>[ |
427 new NameValuePair(name: 'signature', value: preview(object)), | 441 new NameValuePair(name: 'signature', value: preview(object)), |
428 new NameValuePair( | 442 new NameValuePair( |
429 name: 'JavaScript Function', value: object, skipDart: true) | 443 name: 'JavaScript Function', |
| 444 value: object, |
| 445 config: JsonMLConfig.skipDart) |
430 ]; | 446 ]; |
431 } | 447 } |
432 | 448 |
433 /// Formatter for Dart Map objects. | 449 /// Formatter for Dart Map objects. |
434 class MapFormatter extends ObjectFormatter { | 450 class MapFormatter extends ObjectFormatter { |
435 accept(object) => object is Map; | 451 accept(object) => object is Map; |
436 | 452 |
437 bool hasChildren(object) => true; | 453 bool hasChildren(object) => true; |
438 | 454 |
439 String preview(object) { | 455 String preview(object) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 ret.add(new NameValuePair( | 541 ret.add(new NameValuePair( |
526 name: '[[Implements]]', | 542 name: '[[Implements]]', |
527 value: new HeritageClause('implements', implements()))); | 543 value: new HeritageClause('implements', implements()))); |
528 } | 544 } |
529 var mixins = dart.getMixins(type); | 545 var mixins = dart.getMixins(type); |
530 if (mixins != null && mixins.isNotEmpty) { | 546 if (mixins != null && mixins.isNotEmpty) { |
531 ret.add(new NameValuePair( | 547 ret.add(new NameValuePair( |
532 name: '[[Mixins]]', value: new HeritageClause('mixins', mixins))); | 548 name: '[[Mixins]]', value: new HeritageClause('mixins', mixins))); |
533 } | 549 } |
534 ret.add(new NameValuePair( | 550 ret.add(new NameValuePair( |
535 name: '[[JavaScript View]]', value: entry.object, skipDart: true)); | 551 name: '[[JavaScript View]]', |
| 552 value: entry.object, |
| 553 config: JsonMLConfig.skipDart)); |
536 | 554 |
537 // TODO(jacobr): provide a link to the base class or perhaps the entire | 555 // TODO(jacobr): provide a link to the base class or perhaps the entire |
538 // base class hierarchy as a flat list. | 556 // base class hierarchy as a flat list. |
539 | 557 |
540 if (entry.object is! Type) { | 558 if (entry.object is! Type) { |
541 ret.add(new NameValuePair( | 559 ret.add(new NameValuePair( |
542 name: '[[JavaScript Constructor]]', | 560 name: '[[JavaScript Constructor]]', |
543 value: JSNative.getProperty(entry.object, 'constructor'), | 561 value: JSNative.getProperty(entry.object, 'constructor'), |
544 skipDart: true)); | 562 config: JsonMLConfig.skipDart)); |
545 // TODO(jacobr): add constructors, methods, extended class, and static | 563 // TODO(jacobr): add constructors, methods, extended class, and static |
546 } | 564 } |
547 return ret; | 565 return ret; |
548 } | 566 } |
549 } | 567 } |
550 | 568 |
551 /// Formatter for synthetic MapEntry objects used to display contents of a Map | 569 /// Formatter for synthetic MapEntry objects used to display contents of a Map |
552 /// cleanly. | 570 /// cleanly. |
553 class MapEntryFormatter implements Formatter { | 571 class MapEntryFormatter implements Formatter { |
554 accept(object) => object is MapEntry; | 572 accept(object) => object is MapEntry; |
555 | 573 |
556 String preview(object) { | 574 String preview(object) { |
557 MapEntry entry = object; | 575 MapEntry entry = object; |
558 return '${safePreview(entry.key)} => ${safePreview(entry.value)}'; | 576 return '${safePreview(entry.key)} => ${safePreview(entry.value)}'; |
559 } | 577 } |
560 | 578 |
561 bool hasChildren(object) => true; | 579 bool hasChildren(object) => true; |
562 | 580 |
563 List<NameValuePair> children(object) => <NameValuePair>[ | 581 List<NameValuePair> children(object) => <NameValuePair>[ |
564 new NameValuePair(name: 'key', value: object.key), | 582 new NameValuePair( |
| 583 name: 'key', value: object.key, config: JsonMLConfig.keyToString), |
565 new NameValuePair(name: 'value', value: object.value) | 584 new NameValuePair(name: 'value', value: object.value) |
566 ]; | 585 ]; |
567 } | 586 } |
568 | 587 |
569 /// Formatter for Dart Iterable objects including List and Set. | 588 /// Formatter for Dart Iterable objects including List and Set. |
570 class HeritageClauseFormatter implements Formatter { | 589 class HeritageClauseFormatter implements Formatter { |
571 bool accept(object) => object is HeritageClause; | 590 bool accept(object) => object is HeritageClause; |
572 | 591 |
573 String preview(object) { | 592 String preview(object) { |
574 HeritageClause clause = object; | 593 HeritageClause clause = object; |
(...skipping 12 matching lines...) Expand all Loading... |
587 return ret; | 606 return ret; |
588 } | 607 } |
589 } | 608 } |
590 | 609 |
591 /// This entry point is automatically invoked by the code generated by | 610 /// This entry point is automatically invoked by the code generated by |
592 /// Dart Dev Compiler | 611 /// Dart Dev Compiler |
593 registerDevtoolsFormatter() { | 612 registerDevtoolsFormatter() { |
594 var formatters = [_devtoolsFormatter]; | 613 var formatters = [_devtoolsFormatter]; |
595 JS('', 'dart.global.devtoolsFormatters = #', formatters); | 614 JS('', 'dart.global.devtoolsFormatters = #', formatters); |
596 } | 615 } |
OLD | NEW |