Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 * To generate docs for a library, run this script with the path to an | 6 * To generate docs for a library, run this script with the path to an |
| 7 * entrypoint .dart file, like: | 7 * entrypoint .dart file, like: |
| 8 * | 8 * |
| 9 * $ dart dartdoc.dart foo.dart | 9 * $ dart dartdoc.dart foo.dart |
| 10 * | 10 * |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 568 final List members = docMembersJson(library.declaredMembers); | 568 final List members = docMembersJson(library.declaredMembers); |
| 569 if (!members.isEmpty()) { | 569 if (!members.isEmpty()) { |
| 570 libraryInfo[MEMBERS] = members; | 570 libraryInfo[MEMBERS] = members; |
| 571 } | 571 } |
| 572 | 572 |
| 573 final types = []; | 573 final types = []; |
| 574 for (InterfaceMirror type in orderByName(library.types.getValues())) { | 574 for (InterfaceMirror type in orderByName(library.types.getValues())) { |
| 575 if (type.isPrivate) continue; | 575 if (type.isPrivate) continue; |
| 576 | 576 |
| 577 var typeInfo = {}; | 577 var typeInfo = {}; |
| 578 typeInfo[NAME] = type.simpleName; | 578 typeInfo[NAME] = type.displayName; |
| 579 if (type.isClass) { | 579 if (type.isClass) { |
| 580 typeInfo[KIND] = CLASS; | 580 typeInfo[KIND] = CLASS; |
| 581 } else if (type.isInterface) { | 581 } else if (type.isInterface) { |
| 582 typeInfo[KIND] = INTERFACE; | 582 typeInfo[KIND] = INTERFACE; |
| 583 } else { | 583 } else { |
| 584 assert(type.isTypedef); | 584 assert(type.isTypedef); |
| 585 typeInfo[KIND] = TYPEDEF; | 585 typeInfo[KIND] = TYPEDEF; |
| 586 } | 586 } |
| 587 final List typeMembers = docMembersJson(type.declaredMembers); | 587 final List typeMembers = docMembersJson(type.declaredMembers); |
| 588 if (!typeMembers.isEmpty()) { | 588 if (!typeMembers.isEmpty()) { |
| 589 typeInfo[MEMBERS] = typeMembers; | 589 typeInfo[MEMBERS] = typeMembers; |
| 590 } | 590 } |
| 591 | 591 |
| 592 if (!type.declaration.typeVariables.isEmpty()) { | 592 if (!type.declaration.typeVariables.isEmpty()) { |
| 593 final typeVariables = []; | 593 final typeVariables = []; |
| 594 for (final typeVariable in type.declaration.typeVariables) { | 594 for (final typeVariable in type.declaration.typeVariables) { |
| 595 typeVariables.add(typeVariable.simpleName); | 595 typeVariables.add(typeVariable.displayName); |
| 596 } | 596 } |
| 597 typeInfo[ARGS] = Strings.join(typeVariables, ', '); | 597 typeInfo[ARGS] = Strings.join(typeVariables, ', '); |
| 598 } | 598 } |
| 599 types.add(typeInfo); | 599 types.add(typeInfo); |
| 600 } | 600 } |
| 601 if (!types.isEmpty()) { | 601 if (!types.isEmpty()) { |
| 602 libraryInfo[TYPES] = types; | 602 libraryInfo[TYPES] = types; |
| 603 } | 603 } |
| 604 | 604 |
| 605 libraryList.add(libraryInfo); | 605 libraryList.add(libraryInfo); |
| 606 } | 606 } |
| 607 | 607 |
| 608 List docMembersJson(Map<Object,MemberMirror> memberMap) { | 608 List docMembersJson(Map<Object,MemberMirror> memberMap) { |
| 609 final members = []; | 609 final members = []; |
| 610 for (MemberMirror member in orderByName(memberMap.getValues())) { | 610 for (MemberMirror member in orderByName(memberMap.getValues())) { |
| 611 if (member.isPrivate) continue; | 611 if (member.isPrivate) continue; |
| 612 | 612 |
| 613 var memberInfo = {}; | 613 var memberInfo = {}; |
| 614 if (member.isField) { | 614 if (member.isField) { |
| 615 memberInfo[NAME] = member.simpleName; | |
| 616 memberInfo[KIND] = FIELD; | 615 memberInfo[KIND] = FIELD; |
| 617 } else { | 616 } else { |
| 618 MethodMirror method = member; | 617 MethodMirror method = member; |
| 619 if (method.isConstructor) { | 618 if (method.isConstructor) { |
| 620 if (method.constructorName != '') { | 619 memberInfo[KIND] = CONSTRUCTOR; |
| 621 memberInfo[NAME] = '${method.simpleName}.${method.constructorName}'; | |
| 622 memberInfo[KIND] = CONSTRUCTOR; | |
| 623 } else { | |
| 624 memberInfo[NAME] = member.simpleName; | |
| 625 memberInfo[KIND] = CONSTRUCTOR; | |
| 626 } | |
| 627 } else if (method.isOperator) { | |
| 628 memberInfo[NAME] = '${method.simpleName} ${method.operatorName}'; | |
| 629 memberInfo[KIND] = METHOD; | |
| 630 } else if (method.isSetter) { | 620 } else if (method.isSetter) { |
| 631 memberInfo[NAME] = member.simpleName; | |
| 632 memberInfo[KIND] = SETTER; | 621 memberInfo[KIND] = SETTER; |
| 633 } else if (method.isGetter) { | 622 } else if (method.isGetter) { |
| 634 memberInfo[NAME] = member.simpleName; | |
| 635 memberInfo[KIND] = GETTER; | 623 memberInfo[KIND] = GETTER; |
| 636 } else { | 624 } else { |
| 637 memberInfo[NAME] = member.simpleName; | |
| 638 memberInfo[KIND] = METHOD; | 625 memberInfo[KIND] = METHOD; |
| 639 } | 626 } |
| 640 } | 627 } |
| 628 memberInfo[NAME] = member.displayName; | |
| 641 var anchor = memberAnchor(member); | 629 var anchor = memberAnchor(member); |
| 642 if (anchor != memberInfo[NAME]) { | 630 if (anchor != memberInfo[NAME]) { |
| 643 memberInfo[LINK_NAME] = anchor; | 631 memberInfo[LINK_NAME] = anchor; |
| 644 } | 632 } |
| 645 members.add(memberInfo); | 633 members.add(memberInfo); |
| 646 } | 634 } |
| 647 return members; | 635 return members; |
| 648 } | 636 } |
| 649 | 637 |
| 650 void docNavigation() { | 638 void docNavigation() { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 725 _currentType = null; | 713 _currentType = null; |
| 726 | 714 |
| 727 startFile(libraryUrl(library)); | 715 startFile(libraryUrl(library)); |
| 728 writeHeader('${library.simpleName} Library', | 716 writeHeader('${library.simpleName} Library', |
| 729 [library.simpleName, libraryUrl(library)]); | 717 [library.simpleName, libraryUrl(library)]); |
| 730 writeln('<h2><strong>${library.simpleName}</strong> library</h2>'); | 718 writeln('<h2><strong>${library.simpleName}</strong> library</h2>'); |
| 731 | 719 |
| 732 // Look for a comment for the entire library. | 720 // Look for a comment for the entire library. |
| 733 final comment = getLibraryComment(library); | 721 final comment = getLibraryComment(library); |
| 734 if (comment != null) { | 722 if (comment != null) { |
| 735 writeln('<div class="doc">$comment</div>'); | 723 writeln('<div class="doc">${comment.html}</div>'); |
| 736 } | 724 } |
| 737 | 725 |
| 738 // Document the top-level members. | 726 // Document the top-level members. |
| 739 docMembers(library); | 727 docMembers(library); |
| 740 | 728 |
| 741 // Document the types. | 729 // Document the types. |
| 742 final classes = <InterfaceMirror>[]; | 730 final classes = <InterfaceMirror>[]; |
| 743 final interfaces = <InterfaceMirror>[]; | 731 final interfaces = <InterfaceMirror>[]; |
| 744 final typedefs = <TypedefMirror>[]; | 732 final typedefs = <TypedefMirror>[]; |
| 745 final exceptions = <InterfaceMirror>[]; | 733 final exceptions = <InterfaceMirror>[]; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 771 for (final type in library.types.getValues()) { | 759 for (final type in library.types.getValues()) { |
| 772 if (type.isPrivate) continue; | 760 if (type.isPrivate) continue; |
| 773 | 761 |
| 774 docType(type); | 762 docType(type); |
| 775 } | 763 } |
| 776 } | 764 } |
| 777 | 765 |
| 778 void docTypes(List types, String header) { | 766 void docTypes(List types, String header) { |
| 779 if (types.length == 0) return; | 767 if (types.length == 0) return; |
| 780 | 768 |
| 769 writeln('<div>'); | |
| 781 writeln('<h3>$header</h3>'); | 770 writeln('<h3>$header</h3>'); |
| 782 | 771 |
| 783 for (final type in types) { | 772 for (final type in types) { |
| 784 writeln( | 773 writeln( |
| 785 ''' | 774 ''' |
| 786 <div class="type"> | 775 <div class="type"> |
| 787 <h4> | 776 <h4> |
| 788 ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")} | 777 ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")} |
| 789 </h4> | 778 </h4> |
| 790 </div> | 779 </div> |
| 791 '''); | 780 '''); |
| 792 } | 781 } |
| 782 writeln('</div>'); | |
| 793 } | 783 } |
| 794 | 784 |
| 795 void docType(InterfaceMirror type) { | 785 void docType(InterfaceMirror type) { |
| 796 if (verbose) { | 786 if (verbose) { |
| 797 print('- ${type.simpleName}'); | 787 print('- ${type.simpleName}'); |
| 798 } | 788 } |
| 799 _totalTypes++; | 789 _totalTypes++; |
| 800 _currentType = type; | 790 _currentType = type; |
| 801 | 791 |
| 802 startFile(typeUrl(type)); | 792 startFile(typeUrl(type)); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 816 '${typeName(type)} ${kind}'; | 806 '${typeName(type)} ${kind}'; |
| 817 writeHeader('$typeTitle / ${type.library.simpleName} Library', | 807 writeHeader('$typeTitle / ${type.library.simpleName} Library', |
| 818 [type.library.simpleName, libraryUrl(type.library), | 808 [type.library.simpleName, libraryUrl(type.library), |
| 819 typeName(type), typeUrl(type)]); | 809 typeName(type), typeUrl(type)]); |
| 820 writeln( | 810 writeln( |
| 821 ''' | 811 ''' |
| 822 <h2><strong>${typeName(type, showBounds: true)}</strong> | 812 <h2><strong>${typeName(type, showBounds: true)}</strong> |
| 823 $kind | 813 $kind |
| 824 </h2> | 814 </h2> |
| 825 '''); | 815 '''); |
| 816 writeln('<span class="show-inherited">Hide inherited</span>'); | |
|
Lasse Reichstein Nielsen
2012/10/04 07:41:19
Use a button! This is clearly a clickable thing wi
Johnni Winther
2012/10/04 12:46:21
Done.
| |
| 826 | 817 |
| 827 docCode(type.location, getTypeComment(type)); | 818 docCode(type, type.location, getTypeComment(type)); |
| 828 docInheritance(type); | 819 docInheritance(type); |
| 829 docTypedef(type); | 820 docTypedef(type); |
| 821 | |
| 830 docConstructors(type); | 822 docConstructors(type); |
| 831 docMembers(type); | 823 docMembers(type); |
| 832 | 824 |
| 833 writeTypeFooter(); | 825 writeTypeFooter(); |
| 834 writeFooter(); | 826 writeFooter(); |
| 835 endFile(); | 827 endFile(); |
| 836 } | 828 } |
| 837 | 829 |
| 838 /** Override this to write additional content at the end of a type's page. */ | 830 /** Override this to write additional content at the end of a type's page. */ |
| 839 void writeTypeFooter() { | 831 void writeTypeFooter() { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 914 typeSpan(supertypes[i]); | 906 typeSpan(supertypes[i]); |
| 915 write(' > '); | 907 write(' > '); |
| 916 } | 908 } |
| 917 | 909 |
| 918 // Write this class. | 910 // Write this class. |
| 919 typeSpan(type); | 911 typeSpan(type); |
| 920 writeln('</p>'); | 912 writeln('</p>'); |
| 921 } | 913 } |
| 922 | 914 |
| 923 listTypes(subtypes, 'Subclasses'); | 915 listTypes(subtypes, 'Subclasses'); |
| 924 listTypes(type.interfaces.getValues(), 'Implements'); | 916 listTypes(type.interfaces, 'Implements'); |
| 925 } else { | 917 } else { |
| 926 // Show the default class. | 918 // Show the default class. |
| 927 if (type.defaultType != null) { | 919 if (type.defaultType != null) { |
| 928 listTypes([type.defaultType], 'Default class'); | 920 listTypes([type.defaultType], 'Default class'); |
| 929 } | 921 } |
| 930 | 922 |
| 931 // List extended interfaces. | 923 // List extended interfaces. |
| 932 listTypes(type.interfaces.getValues(), 'Extends'); | 924 listTypes(type.interfaces, 'Extends'); |
| 933 | 925 |
| 934 // List subinterfaces and implementing classes. | 926 // List subinterfaces and implementing classes. |
| 935 final subinterfaces = []; | 927 final subinterfaces = []; |
| 936 final implementing = []; | 928 final implementing = []; |
| 937 | 929 |
| 938 for (final subtype in subtypes) { | 930 for (final subtype in subtypes) { |
| 939 if (subtype.isClass) { | 931 if (subtype.isClass) { |
| 940 implementing.add(subtype); | 932 implementing.add(subtype); |
| 941 } else { | 933 } else { |
| 942 subinterfaces.add(subtype); | 934 subinterfaces.add(subtype); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 961 writeln('<span class="show-code">Code</span>'); | 953 writeln('<span class="show-code">Code</span>'); |
| 962 } | 954 } |
| 963 | 955 |
| 964 write('typedef '); | 956 write('typedef '); |
| 965 annotateType(type, type.definition, type.simpleName); | 957 annotateType(type, type.definition, type.simpleName); |
| 966 | 958 |
| 967 write(''' <a class="anchor-link" href="#${type.simpleName}" | 959 write(''' <a class="anchor-link" href="#${type.simpleName}" |
| 968 title="Permalink to ${type.simpleName}">#</a>'''); | 960 title="Permalink to ${type.simpleName}">#</a>'''); |
| 969 writeln('</h4>'); | 961 writeln('</h4>'); |
| 970 | 962 |
| 971 docCode(type.location, null, showCode: true); | 963 docCode(type, type.location, null, showCode: true); |
| 972 | 964 |
| 973 writeln('</div>'); | 965 writeln('</div>'); |
| 974 } | 966 } |
| 975 | 967 |
| 976 /** Document the constructors for [Type], if any. */ | 968 /** Document the constructors for [Type], if any. */ |
| 977 void docConstructors(InterfaceMirror type) { | 969 void docConstructors(InterfaceMirror type) { |
| 978 final constructors = <MethodMirror>[]; | 970 final constructors = <MethodMirror>[]; |
| 979 for (var constructor in type.constructors.getValues()) { | 971 for (var constructor in type.constructors.getValues()) { |
| 980 if (!constructor.isPrivate) { | 972 if (!constructor.isPrivate) { |
| 981 constructors.add(constructor); | 973 constructors.add(constructor); |
| 982 } | 974 } |
| 983 } | 975 } |
| 984 | 976 |
| 985 if (constructors.length > 0) { | 977 if (constructors.length > 0) { |
| 978 writeln('<div>'); | |
| 986 writeln('<h3>Constructors</h3>'); | 979 writeln('<h3>Constructors</h3>'); |
| 987 constructors.sort((x, y) => x.simpleName.toUpperCase().compareTo( | 980 constructors.sort((x, y) => x.simpleName.toUpperCase().compareTo( |
| 988 y.simpleName.toUpperCase())); | 981 y.simpleName.toUpperCase())); |
| 989 | 982 |
| 990 for (final constructor in constructors) { | 983 for (final constructor in constructors) { |
| 991 docMethod(type, constructor); | 984 docMethod(type, constructor); |
| 992 } | 985 } |
| 986 writeln('</div>'); | |
| 993 } | 987 } |
| 994 } | 988 } |
| 995 | 989 |
| 996 void docMembers(ObjectMirror host) { | 990 void docMembers(ObjectMirror host) { |
| 997 // Collect the different kinds of members. | 991 // Collect the different kinds of members. |
| 998 final staticMethods = []; | 992 final staticMethods = []; |
| 999 final staticFields = []; | 993 final staticFields = []; |
| 994 final memberMap = new Map<String,MemberMirror>(); | |
| 1000 final instanceMethods = []; | 995 final instanceMethods = []; |
| 1001 final instanceFields = []; | 996 final instanceFields = []; |
| 1002 | 997 |
| 1003 for (MemberMirror member in orderByName(host.declaredMembers.getValues())) { | 998 host.declaredMembers.forEach((_, MemberMirror member) { |
|
Lasse Reichstein Nielsen
2012/10/04 07:41:19
Add a host.forEachDeclaredMember method instead of
Johnni Winther
2012/10/04 12:46:21
[declaredMembers] is also used for lookup where th
| |
| 1004 if (member.isPrivate) continue; | 999 if (member.isPrivate) return; |
| 1000 if (member.isStatic) { | |
| 1001 if (member.isMethod) { | |
| 1002 staticMethods.add(member); | |
| 1003 } else if (member.isField) { | |
| 1004 staticFields.add(member); | |
| 1005 } | |
| 1006 } | |
| 1007 }); | |
| 1005 | 1008 |
| 1006 final methods = member.isStatic ? staticMethods : instanceMethods; | 1009 if (host is InterfaceMirror) { |
| 1007 final fields = member.isStatic ? staticFields : instanceFields; | 1010 var iterable = new HierarchyIterable(host, includeType: true); |
| 1011 for (InterfaceMirror type in iterable) { | |
| 1012 type.declaredMembers.forEach((_, MemberMirror member) { | |
| 1013 if (member.isPrivate) return; | |
| 1014 if (!member.isStatic) { | |
| 1015 memberMap.putIfAbsent(member.simpleName, () => member); | |
| 1016 } | |
| 1017 }); | |
| 1018 } | |
| 1019 } | |
| 1008 | 1020 |
| 1021 memberMap.forEach((_, MemberMirror member) { | |
| 1009 if (member.isMethod) { | 1022 if (member.isMethod) { |
| 1010 methods.add(member); | 1023 instanceMethods.add(member); |
| 1011 } else if (member.isField) { | 1024 } else if (member.isField) { |
| 1012 fields.add(member); | 1025 instanceFields.add(member); |
| 1013 } | 1026 } |
| 1027 }); | |
| 1028 | |
| 1029 if (staticFields.length > 0) { | |
| 1030 final title = host is LibraryMirror ? 'Variables' : 'Static Fields'; | |
| 1031 writeln('<div>'); | |
| 1032 writeln('<h3>$title</h3>'); | |
| 1033 for (final field in orderByName(staticFields)) { | |
| 1034 docField(host, field); | |
| 1035 } | |
| 1036 writeln('</div>'); | |
| 1014 } | 1037 } |
| 1015 | 1038 |
| 1016 if (staticMethods.length > 0) { | 1039 if (staticMethods.length > 0) { |
| 1017 final title = host is LibraryMirror ? 'Functions' : 'Static Methods'; | 1040 final title = host is LibraryMirror ? 'Functions' : 'Static Methods'; |
| 1041 writeln('<div>'); | |
|
Lasse Reichstein Nielsen
2012/10/04 07:41:19
Why wrap it in a div if it doesn't even have a cla
Johnni Winther
2012/10/04 12:46:21
Not quite sure. It was requested in dartbug.com/11
| |
| 1018 writeln('<h3>$title</h3>'); | 1042 writeln('<h3>$title</h3>'); |
| 1019 for (final method in orderByName(staticMethods)) { | 1043 for (final method in orderByName(staticMethods)) { |
| 1020 docMethod(host, method); | 1044 docMethod(host, method); |
| 1021 } | 1045 } |
| 1046 writeln('</div>'); | |
| 1022 } | 1047 } |
| 1023 | 1048 |
| 1024 if (staticFields.length > 0) { | 1049 if (instanceFields.length > 0) { |
| 1025 final title = host is LibraryMirror ? 'Variables' : 'Static Fields'; | 1050 writeln('<div>'); |
| 1026 writeln('<h3>$title</h3>'); | 1051 writeln('<h3>Fields</h3>'); |
| 1027 for (final field in orderByName(staticFields)) { | 1052 for (final field in orderByName(instanceFields)) { |
| 1028 docField(host, field); | 1053 docField(host, field); |
| 1029 } | 1054 } |
| 1055 writeln('</div>'); | |
| 1030 } | 1056 } |
| 1031 | 1057 |
| 1032 if (instanceMethods.length > 0) { | 1058 if (instanceMethods.length > 0) { |
| 1059 writeln('<div>'); | |
| 1033 writeln('<h3>Methods</h3>'); | 1060 writeln('<h3>Methods</h3>'); |
| 1034 for (final method in orderByName(instanceMethods)) { | 1061 for (final method in orderByName(instanceMethods)) { |
| 1035 docMethod(host, method); | 1062 docMethod(host, method); |
| 1036 } | 1063 } |
| 1037 } | 1064 writeln('</div>'); |
| 1038 | |
| 1039 if (instanceFields.length > 0) { | |
| 1040 writeln('<h3>Fields</h3>'); | |
| 1041 for (final field in orderByName(instanceFields)) { | |
| 1042 docField(host, field); | |
| 1043 } | |
| 1044 } | 1065 } |
| 1045 } | 1066 } |
| 1046 | 1067 |
| 1047 /** | 1068 /** |
| 1048 * Documents the [method] in type [type]. Handles all kinds of methods | 1069 * Documents the [method] in type [type]. Handles all kinds of methods |
| 1049 * including getters, setters, and constructors. | 1070 * including getters, setters, and constructors. |
| 1050 */ | 1071 */ |
| 1051 void docMethod(ObjectMirror host, MethodMirror method) { | 1072 void docMethod(ObjectMirror host, MethodMirror method) { |
| 1052 _totalMembers++; | 1073 _totalMembers++; |
| 1053 _currentMember = method; | 1074 _currentMember = method; |
| 1054 | 1075 |
| 1055 bool showCode = includeSource && !method.isAbstract; | 1076 bool showCode = includeSource && !method.isAbstract; |
| 1077 bool inherited = host != method.surroundingDeclaration; | |
| 1056 | 1078 |
| 1057 writeln('<div class="method"><h4 id="${memberAnchor(method)}">'); | 1079 writeln('<div class="method${inherited ? ' inherited': ''}">' |
| 1080 '<h4 id="${memberAnchor(method)}">'); | |
| 1058 | 1081 |
| 1059 if (showCode) { | 1082 if (showCode) { |
| 1060 writeln('<span class="show-code">Code</span>'); | 1083 writeln('<span class="show-code">Code</span>'); |
| 1061 } | 1084 } |
| 1062 | 1085 |
| 1063 if (method.isConstructor) { | 1086 if (method.isConstructor) { |
| 1064 if (method.isFactory) { | 1087 if (method.isFactory) { |
| 1065 write('factory '); | 1088 write('factory '); |
| 1066 } else { | 1089 } else { |
| 1067 write(method.isConst ? 'const ' : 'new '); | 1090 write(method.isConst ? 'const ' : 'new '); |
| 1068 } | 1091 } |
| 1069 } else if (method.isAbstract) { | 1092 } else if (method.isAbstract) { |
| 1070 write('abstract '); | 1093 write('abstract '); |
| 1071 } | 1094 } |
| 1072 | 1095 |
| 1073 if (method.constructorName == null) { | 1096 if (!method.isConstructor) { |
| 1074 annotateType(host, method.returnType); | 1097 annotateType(host, method.returnType); |
| 1075 } | 1098 } |
| 1076 | 1099 |
| 1077 var name = method.simpleName; | 1100 var name = method.displayName; |
| 1078 // Translate specially-named methods: getters, setters, operators. | 1101 // Translate specially-named methods: getters, setters, operators. |
| 1079 if (method.isGetter) { | 1102 if (method.isGetter) { |
| 1080 // Getter. | 1103 // Getter. |
| 1081 name = 'get $name'; | 1104 name = 'get $name'; |
| 1082 } else if (method.isSetter) { | 1105 } else if (method.isSetter) { |
| 1083 // Setter. | 1106 // Setter. |
| 1084 name = 'set $name'; | 1107 name = 'set $name'; |
| 1085 } else if (method.isOperator) { | |
| 1086 name = 'operator ${method.operatorName}'; | |
| 1087 } | 1108 } |
| 1088 | 1109 |
| 1089 write('<strong>$name</strong>'); | 1110 write('<strong>$name</strong>'); |
| 1090 | 1111 |
| 1091 // Named constructors. | |
| 1092 if (method.constructorName != null && method.constructorName != '') { | |
| 1093 write('.'); | |
| 1094 write(method.constructorName); | |
| 1095 } | |
| 1096 | |
| 1097 docParamList(host, method.parameters); | 1112 docParamList(host, method.parameters); |
| 1098 | 1113 |
| 1099 var prefix = host is LibraryMirror ? '' : '${typeName(host)}.'; | 1114 var prefix = host is LibraryMirror ? '' : '${typeName(host)}.'; |
| 1100 write(''' <a class="anchor-link" href="#${memberAnchor(method)}" | 1115 write(''' <a class="anchor-link" href="#${memberAnchor(method)}" |
| 1101 title="Permalink to $prefix$name">#</a>'''); | 1116 title="Permalink to $prefix$name">#</a>'''); |
| 1102 writeln('</h4>'); | 1117 writeln('</h4>'); |
| 1103 | 1118 |
| 1104 docCode(method.location, getMethodComment(method), showCode: showCode); | 1119 if (inherited) { |
| 1120 write('<div class="inherited-from">inherited from '); | |
| 1121 annotateType(host, method.surroundingDeclaration); | |
| 1122 write('</div>'); | |
| 1123 } | |
| 1124 | |
| 1125 docCode(host, method.location, getMemberComment(method), showCode: showCode) ; | |
| 1105 | 1126 |
| 1106 writeln('</div>'); | 1127 writeln('</div>'); |
| 1107 } | 1128 } |
| 1108 | 1129 |
| 1109 /** Documents the field [field] of type [type]. */ | 1130 /** Documents the field [field] of type [type]. */ |
| 1110 void docField(ObjectMirror host, FieldMirror field) { | 1131 void docField(ObjectMirror host, FieldMirror field) { |
| 1111 _totalMembers++; | 1132 _totalMembers++; |
| 1112 _currentMember = field; | 1133 _currentMember = field; |
| 1113 | 1134 |
| 1114 writeln('<div class="field"><h4 id="${memberAnchor(field)}">'); | 1135 bool inherited = host != field.surroundingDeclaration; |
| 1136 | |
| 1137 writeln('<div class="field${inherited ? ' inherited' : ''}">' | |
| 1138 '<h4 id="${memberAnchor(field)}">'); | |
| 1115 | 1139 |
| 1116 if (includeSource) { | 1140 if (includeSource) { |
| 1117 writeln('<span class="show-code">Code</span>'); | 1141 writeln('<span class="show-code">Code</span>'); |
| 1118 } | 1142 } |
| 1119 | 1143 |
| 1120 if (field.isFinal) { | 1144 if (field.isFinal) { |
| 1121 write('final '); | 1145 write('final '); |
| 1122 } else if (field.type.isDynamic) { | 1146 } else if (field.type.isDynamic) { |
| 1123 write('var '); | 1147 write('var '); |
| 1124 } | 1148 } |
| 1125 | 1149 |
| 1126 annotateType(host, field.type); | 1150 annotateType(host, field.type); |
| 1127 var prefix = host is LibraryMirror ? '' : '${typeName(host)}.'; | 1151 var prefix = host is LibraryMirror ? '' : '${typeName(host)}.'; |
| 1128 write( | 1152 write( |
| 1129 ''' | 1153 ''' |
| 1130 <strong>${field.simpleName}</strong> <a class="anchor-link" | 1154 <strong>${field.simpleName}</strong> <a class="anchor-link" |
| 1131 href="#${memberAnchor(field)}" | 1155 href="#${memberAnchor(field)}" |
| 1132 title="Permalink to $prefix${field.simpleName}">#</a> | 1156 title="Permalink to $prefix${field.simpleName}">#</a> |
| 1133 </h4> | 1157 </h4> |
| 1134 '''); | 1158 '''); |
| 1135 | 1159 |
| 1136 docCode(field.location, getFieldComment(field), showCode: true); | 1160 if (inherited) { |
| 1161 write('<div class="inherited-from">inherited from '); | |
| 1162 annotateType(host, field.surroundingDeclaration); | |
| 1163 write('</div>'); | |
| 1164 } | |
| 1165 | |
| 1166 docCode(host, field.location, getMemberComment(field), showCode: true); | |
| 1167 | |
| 1137 writeln('</div>'); | 1168 writeln('</div>'); |
| 1138 } | 1169 } |
| 1139 | 1170 |
| 1140 void docParamList(ObjectMirror enclosingType, | 1171 void docParamList(ObjectMirror enclosingType, |
| 1141 List<ParameterMirror> parameters) { | 1172 List<ParameterMirror> parameters) { |
| 1142 write('('); | 1173 write('('); |
| 1143 bool first = true; | 1174 bool first = true; |
| 1144 bool inOptionals = false; | 1175 bool inOptionals = false; |
| 1145 for (final parameter in parameters) { | 1176 for (final parameter in parameters) { |
| 1146 if (!first) write(', '); | 1177 if (!first) write(', '); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1162 } | 1193 } |
| 1163 | 1194 |
| 1164 if (inOptionals) write(']'); | 1195 if (inOptionals) write(']'); |
| 1165 write(')'); | 1196 write(')'); |
| 1166 } | 1197 } |
| 1167 | 1198 |
| 1168 /** | 1199 /** |
| 1169 * Documents the code contained within [span] with [comment]. If [showCode] | 1200 * Documents the code contained within [span] with [comment]. If [showCode] |
| 1170 * is `true` (and [includeSource] is set), also includes the source code. | 1201 * is `true` (and [includeSource] is set), also includes the source code. |
| 1171 */ | 1202 */ |
| 1172 void docCode(Location location, String comment, [bool showCode = false]) { | 1203 void docCode(ObjectMirror host, Location location, DocComment comment, |
| 1204 [bool showCode = false]) { | |
| 1173 writeln('<div class="doc">'); | 1205 writeln('<div class="doc">'); |
| 1174 if (comment != null) { | 1206 if (comment != null) { |
| 1175 writeln(comment); | 1207 if (comment.inheritedFrom !== null) { |
| 1208 writeln('<div class="inherited">'); | |
| 1209 writeln(comment.html); | |
| 1210 write('<div class="docs-inherited-from">docs inherited from '); | |
| 1211 annotateType(host, comment.inheritedFrom); | |
| 1212 write('</div>'); | |
| 1213 writeln('</div>'); | |
| 1214 } else { | |
| 1215 writeln(comment.html); | |
| 1216 } | |
| 1176 } | 1217 } |
| 1177 | 1218 |
| 1178 if (includeSource && showCode) { | 1219 if (includeSource && showCode) { |
| 1179 writeln('<pre class="source">'); | 1220 writeln('<pre class="source">'); |
| 1180 writeln(md.escapeHtml(unindentCode(location))); | 1221 writeln(md.escapeHtml(unindentCode(location))); |
| 1181 writeln('</pre>'); | 1222 writeln('</pre>'); |
| 1182 } | 1223 } |
| 1183 | 1224 |
| 1184 writeln('</div>'); | 1225 writeln('</div>'); |
| 1185 } | 1226 } |
| 1186 | 1227 |
| 1228 DocComment createDocComment(String text, [InterfaceMirror inheritedFrom]) => | |
| 1229 new DocComment(text, inheritedFrom); | |
| 1230 | |
| 1187 | 1231 |
| 1188 /** Get the doc comment associated with the given library. */ | 1232 /** Get the doc comment associated with the given library. */ |
| 1189 String getLibraryComment(LibraryMirror library) { | 1233 DocComment getLibraryComment(LibraryMirror library) { |
| 1190 // Look for a comment for the entire library. | 1234 // Look for a comment for the entire library. |
| 1191 final comment = _comments.findLibrary(library.location.source); | 1235 final comment = _comments.findLibrary(library.location.source); |
| 1192 if (comment != null) { | 1236 if (comment == null) return null; |
| 1193 return md.markdownToHtml(comment); | 1237 return createDocComment(comment); |
| 1194 } | |
| 1195 return null; | |
| 1196 } | 1238 } |
| 1197 | 1239 |
| 1198 /** Get the doc comment associated with the given type. */ | 1240 /** Get the doc comment associated with the given type. */ |
| 1199 String getTypeComment(TypeMirror type) { | 1241 DocComment getTypeComment(TypeMirror type) { |
| 1200 String comment = _comments.find(type.location); | 1242 String comment = _comments.find(type.location); |
| 1201 if (comment == null) return null; | 1243 if (comment == null) return null; |
| 1202 return commentToHtml(comment); | 1244 return createDocComment(comment); |
| 1203 } | 1245 } |
| 1204 | 1246 |
| 1205 /** Get the doc comment associated with the given method. */ | 1247 /** |
| 1206 String getMethodComment(MethodMirror method) { | 1248 * Get the doc comment associated with the given member. |
| 1207 String comment = _comments.find(method.location); | 1249 * |
| 1250 * If no comment was found on the member, the hierarchy is traversed to find | |
| 1251 * an inherited comment, favouring comments inherited from classes over | |
| 1252 * comments inherited from interfaces. | |
| 1253 */ | |
| 1254 DocComment getMemberComment(MemberMirror member) { | |
| 1255 String comment = _comments.find(member.location); | |
| 1256 InterfaceMirror inheritedFrom = null; | |
| 1257 if (comment == null) { | |
| 1258 if (member.surroundingDeclaration is InterfaceMirror) { | |
| 1259 var iterable = | |
| 1260 new HierarchyIterable(member.surroundingDeclaration, | |
| 1261 includeType: false); | |
| 1262 for (InterfaceMirror type in iterable) { | |
| 1263 var inheritedMember = type.declaredMembers[member.simpleName]; | |
| 1264 if (inheritedMember is MemberMirror) { | |
| 1265 comment = _comments.find(inheritedMember.location); | |
| 1266 if (comment != null) { | |
| 1267 inheritedFrom = type; | |
| 1268 break; | |
| 1269 } | |
| 1270 } | |
| 1271 } | |
| 1272 } | |
| 1273 } | |
| 1208 if (comment == null) return null; | 1274 if (comment == null) return null; |
| 1209 return commentToHtml(comment); | 1275 return createDocComment(comment, inheritedFrom); |
| 1210 } | 1276 } |
| 1211 | 1277 |
| 1212 /** Get the doc comment associated with the given field. */ | |
| 1213 String getFieldComment(FieldMirror field) { | |
| 1214 String comment = _comments.find(field.location); | |
| 1215 if (comment == null) return null; | |
| 1216 return commentToHtml(comment); | |
| 1217 } | |
| 1218 | |
| 1219 String commentToHtml(String comment) => md.markdownToHtml(comment); | |
| 1220 | |
| 1221 /** | 1278 /** |
| 1222 * Converts [fullPath] which is understood to be a full path from the root of | 1279 * Converts [fullPath] which is understood to be a full path from the root of |
| 1223 * the generated docs to one relative to the current file. | 1280 * the generated docs to one relative to the current file. |
| 1224 */ | 1281 */ |
| 1225 String relativePath(String fullPath) { | 1282 String relativePath(String fullPath) { |
| 1226 // Don't make it relative if it's an absolute path. | 1283 // Don't make it relative if it's an absolute path. |
| 1227 if (isAbsolute(fullPath)) return fullPath; | 1284 if (isAbsolute(fullPath)) return fullPath; |
| 1228 | 1285 |
| 1229 // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do | 1286 // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do |
| 1230 // this if the paths overlap. | 1287 // this if the paths overlap. |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1259 } | 1316 } |
| 1260 | 1317 |
| 1261 /** Gets the URL for the documentation for [member]. */ | 1318 /** Gets the URL for the documentation for [member]. */ |
| 1262 String memberUrl(MemberMirror member) { | 1319 String memberUrl(MemberMirror member) { |
| 1263 String url = typeUrl(member.surroundingDeclaration); | 1320 String url = typeUrl(member.surroundingDeclaration); |
| 1264 return '$url#${memberAnchor(member)}'; | 1321 return '$url#${memberAnchor(member)}'; |
| 1265 } | 1322 } |
| 1266 | 1323 |
| 1267 /** Gets the anchor id for the document for [member]. */ | 1324 /** Gets the anchor id for the document for [member]. */ |
| 1268 String memberAnchor(MemberMirror member) { | 1325 String memberAnchor(MemberMirror member) { |
| 1269 if (member.isField) { | 1326 return member.simpleName; |
| 1270 return member.simpleName; | |
| 1271 } | |
| 1272 MethodMirror method = member; | |
| 1273 if (method.isConstructor) { | |
| 1274 if (method.constructorName == '') { | |
| 1275 return method.simpleName; | |
| 1276 } else { | |
| 1277 return '${method.simpleName}.${method.constructorName}'; | |
| 1278 } | |
| 1279 } else if (method.isOperator) { | |
| 1280 return '${method.simpleName} ${method.operatorName}'; | |
| 1281 } else if (method.isSetter) { | |
| 1282 return '${method.simpleName}='; | |
| 1283 } else { | |
| 1284 return method.simpleName; | |
| 1285 } | |
| 1286 } | 1327 } |
| 1287 | 1328 |
| 1288 /** | 1329 /** |
| 1289 * Creates a hyperlink. Handles turning the [href] into an appropriate | 1330 * Creates a hyperlink. Handles turning the [href] into an appropriate |
| 1290 * relative path from the current file. | 1331 * relative path from the current file. |
| 1291 */ | 1332 */ |
| 1292 String a(String href, String contents, [String css]) { | 1333 String a(String href, String contents, [String css]) { |
| 1293 // Mark outgoing external links, mainly so we can style them. | 1334 // Mark outgoing external links, mainly so we can style them. |
| 1294 final rel = isAbsolute(href) ? ' ref="external"' : ''; | 1335 final rel = isAbsolute(href) ? ' ref="external"' : ''; |
| 1295 final cssClass = css == null ? '' : ' class="$css"'; | 1336 final cssClass = css == null ? '' : ' class="$css"'; |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1469 if (parameter.simpleName == name) { | 1510 if (parameter.simpleName == name) { |
| 1470 final element = new md.Element.text('span', name); | 1511 final element = new md.Element.text('span', name); |
| 1471 element.attributes['class'] = 'param'; | 1512 element.attributes['class'] = 'param'; |
| 1472 return element; | 1513 return element; |
| 1473 } | 1514 } |
| 1474 } | 1515 } |
| 1475 } | 1516 } |
| 1476 | 1517 |
| 1477 // See if it's another member of the current type. | 1518 // See if it's another member of the current type. |
| 1478 if (currentType != null) { | 1519 if (currentType != null) { |
| 1479 final foundMember = findMirror(currentType.declaredMembers, name); | 1520 final foundMember = currentType.declaredMembers[name]; |
| 1480 if (foundMember != null) { | 1521 if (foundMember != null) { |
| 1481 return makeLink(memberUrl(foundMember)); | 1522 return makeLink(memberUrl(foundMember)); |
| 1482 } | 1523 } |
| 1483 } | 1524 } |
| 1484 | 1525 |
| 1485 // See if it's another type or a member of another type in the current | 1526 // See if it's another type or a member of another type in the current |
| 1486 // library. | 1527 // library. |
| 1487 if (currentLibrary != null) { | 1528 if (currentLibrary != null) { |
| 1488 // See if it's a constructor | 1529 // See if it's a constructor |
| 1489 final constructorLink = (() { | 1530 final constructorLink = (() { |
| 1490 final match = | 1531 final match = |
| 1491 new RegExp(r'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name); | 1532 new RegExp(r'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name); |
| 1492 if (match == null) return; | 1533 if (match == null) return; |
| 1493 InterfaceMirror foundtype = findMirror(currentLibrary.types, match[1]); | 1534 String typeName = match[1]; |
| 1535 InterfaceMirror foundtype = currentLibrary.types[typeName]; | |
| 1494 if (foundtype == null) return; | 1536 if (foundtype == null) return; |
| 1537 String constructorName = | |
| 1538 match[2] == null ? typeName : '$typeName.${match[2]}'; | |
|
Lasse Reichstein Nielsen
2012/10/04 07:41:19
I recommend parentheses around any non-trivial con
Johnni Winther
2012/10/04 12:46:21
Done.
| |
| 1495 final constructor = | 1539 final constructor = |
| 1496 findMirror(foundtype.constructors, | 1540 foundtype.constructors[constructorName]; |
| 1497 match[2] == null ? '' : match[2]); | |
| 1498 if (constructor == null) return; | 1541 if (constructor == null) return; |
| 1499 return makeLink(memberUrl(constructor)); | 1542 return makeLink(memberUrl(constructor)); |
| 1500 })(); | 1543 })(); |
| 1501 if (constructorLink != null) return constructorLink; | 1544 if (constructorLink != null) return constructorLink; |
| 1502 | 1545 |
| 1503 // See if it's a member of another type | 1546 // See if it's a member of another type |
| 1504 final foreignMemberLink = (() { | 1547 final foreignMemberLink = (() { |
| 1505 final match = new RegExp(r'([\w$]+)\.([\w$]+)').firstMatch(name); | 1548 final match = new RegExp(r'([\w$]+)\.([\w$]+)').firstMatch(name); |
| 1506 if (match == null) return; | 1549 if (match == null) return; |
| 1507 InterfaceMirror foundtype = findMirror(currentLibrary.types, match[1]); | 1550 InterfaceMirror foundtype = currentLibrary.types[match[1]]; |
| 1508 if (foundtype == null) return; | 1551 if (foundtype == null) return; |
| 1509 MemberMirror foundMember = findMirror(foundtype.declaredMembers, match[2 ]); | 1552 MemberMirror foundMember = foundtype.declaredMembers[match[2]]; |
| 1510 if (foundMember == null) return; | 1553 if (foundMember == null) return; |
| 1511 return makeLink(memberUrl(foundMember)); | 1554 return makeLink(memberUrl(foundMember)); |
| 1512 })(); | 1555 })(); |
| 1513 if (foreignMemberLink != null) return foreignMemberLink; | 1556 if (foreignMemberLink != null) return foreignMemberLink; |
| 1514 | 1557 |
| 1515 InterfaceMirror foundType = findMirror(currentLibrary.types, name); | 1558 InterfaceMirror foundType = currentLibrary.types[name]; |
| 1516 if (foundType != null) { | 1559 if (foundType != null) { |
| 1517 return makeLink(typeUrl(foundType)); | 1560 return makeLink(typeUrl(foundType)); |
| 1518 } | 1561 } |
| 1519 | 1562 |
| 1520 // See if it's a top-level member in the current library. | 1563 // See if it's a top-level member in the current library. |
| 1521 MemberMirror foundMember = findMirror(currentLibrary.declaredMembers, name ); | 1564 MemberMirror foundMember = currentLibrary.declaredMembers[name]; |
| 1522 if (foundMember != null) { | 1565 if (foundMember != null) { |
| 1523 return makeLink(memberUrl(foundMember)); | 1566 return makeLink(memberUrl(foundMember)); |
| 1524 } | 1567 } |
| 1525 } | 1568 } |
| 1526 | 1569 |
| 1527 // TODO(rnystrom): Should also consider: | 1570 // TODO(rnystrom): Should also consider: |
| 1528 // * Names imported by libraries this library imports. | 1571 // * Names imported by libraries this library imports. |
| 1529 // * Type parameters of the enclosing type. | 1572 // * Type parameters of the enclosing type. |
| 1530 | 1573 |
| 1531 return new md.Element.text('code', name); | 1574 return new md.Element.text('code', name); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1575 | 1618 |
| 1576 /** | 1619 /** |
| 1577 * Used to report an unexpected error in the DartDoc tool or the | 1620 * Used to report an unexpected error in the DartDoc tool or the |
| 1578 * underlying data | 1621 * underlying data |
| 1579 */ | 1622 */ |
| 1580 class InternalError { | 1623 class InternalError { |
| 1581 final String message; | 1624 final String message; |
| 1582 const InternalError(this.message); | 1625 const InternalError(this.message); |
| 1583 String toString() => "InternalError: '$message'"; | 1626 String toString() => "InternalError: '$message'"; |
| 1584 } | 1627 } |
| 1628 | |
| 1629 class DocComment { | |
| 1630 final String text; | |
| 1631 | |
| 1632 /** | |
| 1633 * Non-null if the comment is inherited from another declaration. | |
| 1634 */ | |
| 1635 final InterfaceMirror inheritedFrom; | |
| 1636 | |
| 1637 DocComment(this.text, [this.inheritedFrom = null]) { | |
| 1638 assert(text != null && !text.trim().isEmpty()); | |
| 1639 } | |
| 1640 | |
| 1641 String get html => md.markdownToHtml(text); | |
|
Lasse Reichstein Nielsen
2012/10/04 07:41:19
Why isn't the "inherited from" HTML added by this
Johnni Winther
2012/10/04 12:46:21
The functionality might fit in the DocComment clas
| |
| 1642 | |
| 1643 String toString() => text; | |
| 1644 } | |
| OLD | NEW |