OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library docgen.models.library; | |
6 | |
7 import 'dart:io'; | |
8 | |
9 import 'package:markdown/markdown.dart' as markdown; | |
10 | |
11 import '../exports/source_mirrors.dart'; | |
12 import '../exports/mirrors_util.dart' as dart2js_util; | |
13 | |
14 import '../library_helpers.dart'; | |
15 import '../package_helpers.dart'; | |
16 | |
17 import 'class.dart'; | |
18 import 'dummy_mirror.dart'; | |
19 import 'indexable.dart'; | |
20 import 'method.dart'; | |
21 import 'model_helpers.dart'; | |
22 import 'typedef.dart'; | |
23 import 'variable.dart'; | |
24 | |
25 /// A class containing contents of a Dart library. | |
26 class Library extends Indexable { | |
27 final Map<String, Class> classes = {}; | |
28 final Map<String, Typedef> typedefs = {}; | |
29 final Map<String, Class> errors = {}; | |
30 | |
31 /// Top-level variables in the library. | |
32 Map<String, Variable> variables; | |
33 | |
34 /// Top-level functions in the library. | |
35 Map<String, Method> functions; | |
36 | |
37 String packageName = ''; | |
38 bool _hasBeenCheckedForPackage = false; | |
39 String packageIntro; | |
40 | |
41 Indexable get owner => const _LibraryOwner(); | |
42 | |
43 Library get owningLibrary => this; | |
44 | |
45 /// Returns the [Library] for the given [mirror] if it has already been | |
46 /// created, else creates it. | |
47 factory Library(LibraryMirror mirror) { | |
48 var library = getDocgenObject(mirror); | |
49 if (library is DummyMirror) { | |
50 library = new Library._(mirror); | |
51 } | |
52 return library; | |
53 } | |
54 | |
55 Library._(LibraryMirror libraryMirror) : super(libraryMirror) { | |
56 var exported = calcExportedItems(libraryMirror, {}); | |
57 var exportedClasses = addAll(exported['classes'], | |
58 dart2js_util.typesOf(libraryMirror.declarations)); | |
59 updateLibraryPackage(mirror); | |
60 exportedClasses.forEach((String mirrorName, TypeMirror mirror) { | |
61 if (mirror is TypedefMirror) { | |
62 // This is actually a Dart2jsTypedefMirror, and it does define value, | |
63 // but we don't have visibility to that type. | |
64 if (includePrivateMembers || !mirror.isPrivate) { | |
65 typedefs[dart2js_util.nameOf(mirror)] = new Typedef(mirror, this); | |
66 } | |
67 } else if (mirror is ClassMirror) { | |
68 var clazz = new Class(mirror, this); | |
69 | |
70 if (clazz.isError()) { | |
71 errors[dart2js_util.nameOf(mirror)] = clazz; | |
72 } else { | |
73 classes[dart2js_util.nameOf(mirror)] = clazz; | |
74 } | |
75 } else { | |
76 throw new ArgumentError( | |
77 '${dart2js_util.nameOf(mirror)} - no class type match. '); | |
78 } | |
79 }); | |
80 this.functions = createMethods(addAll(exported['methods'], | |
81 libraryMirror.declarations.values.where( | |
82 (mirror) => mirror is MethodMirror)).values, this); | |
83 this.variables = createVariables(addAll(exported['variables'], | |
84 dart2js_util.variablesOf(libraryMirror.declarations)).values, this); | |
85 } | |
86 | |
87 /// Look for the specified name starting with the current member, and | |
88 /// progressively working outward to the current library scope. | |
89 String findElementInScope(String name) { | |
90 var lookupFunc = determineLookupFunc(name); | |
91 var libraryScope = lookupFunc(mirror, name); | |
92 if (libraryScope != null) { | |
93 var result = getDocgenObject(libraryScope, this); | |
94 if (result is DummyMirror) return packagePrefix + result.docName; | |
95 return result.packagePrefix + result.docName; | |
96 } | |
97 return super.findElementInScope(name); | |
98 } | |
99 | |
100 String getMdnComment() => ''; | |
101 | |
102 /// For a library's [mirror], determine the name of the package (if any) we | |
103 /// believe it came from (because of its file URI). | |
104 /// | |
105 /// If no package could be determined, we return an empty string. | |
106 void updateLibraryPackage(LibraryMirror mirror) { | |
107 if (mirror == null) return; | |
108 if (_hasBeenCheckedForPackage) return; | |
109 _hasBeenCheckedForPackage = true; | |
110 if (mirror.uri.scheme != 'file') return; | |
111 packageName = getPackageName(mirror); | |
112 // Associate the package readme with all the libraries. This is a bit | |
113 // wasteful, but easier than trying to figure out which partial match | |
114 // is best. | |
115 packageIntro = _packageIntro(getPackageDirectory(mirror)); | |
116 } | |
117 | |
118 String _packageIntro(packageDir) { | |
119 if (packageDir == null) return null; | |
120 var dir = new Directory(packageDir); | |
121 var files = dir.listSync(); | |
122 var readmes = files.where((FileSystemEntity each) => (each is File && | |
123 each.path.substring(packageDir.length + 1, each.path.length) | |
124 .startsWith('README'))).toList(); | |
125 if (readmes.isEmpty) return ''; | |
126 // If there are multiples, pick the shortest name. | |
127 readmes.sort((a, b) => a.path.length.compareTo(b.path.length)); | |
128 var readme = readmes.first; | |
129 var linkResolver = (name) => globalFixReference(name); | |
130 var contents = markdown.markdownToHtml(readme | |
131 .readAsStringSync(), linkResolver: linkResolver, | |
132 inlineSyntaxes: MARKDOWN_SYNTAXES); | |
133 return contents; | |
134 } | |
135 | |
136 String get packagePrefix => packageName == null || packageName.isEmpty ? | |
137 '' : '$packageName/'; | |
138 | |
139 Map get previewMap { | |
140 var map = {'packageName': packageName}; | |
141 map.addAll(super.previewMap); | |
142 if (packageIntro != null) { | |
143 map['packageIntro'] = packageIntro; | |
144 } | |
145 var version = packageVersion(mirror); | |
146 if (version != '' && version != null) map['version'] = version; | |
147 return map; | |
148 } | |
149 | |
150 String get name => docName; | |
151 | |
152 String get docName => getLibraryDocName(mirror); | |
153 | |
154 /// Generates a map describing the [Library] object. | |
155 Map toMap() => { | |
156 'name': name, | |
157 'qualifiedName': qualifiedName, | |
158 'comment': comment, | |
159 'variables': recurseMap(variables), | |
160 'functions': expandMethodMap(functions), | |
161 'classes': { | |
162 'class': classes.values.where((c) => c.isVisible) | |
163 .map((e) => e.previewMap).toList(), | |
164 'typedef': recurseMap(typedefs), | |
165 'error': errors.values.where((e) => e.isVisible) | |
166 .map((e) => e.previewMap).toList() | |
167 }, | |
168 'packageName': packageName, | |
169 'packageIntro': packageIntro | |
170 }; | |
171 | |
172 String get typeName => 'library'; | |
173 | |
174 bool isValidMirror(DeclarationMirror mirror) => mirror is LibraryMirror; | |
175 } | |
176 | |
177 /// Dummy implementation of Indexable to represent the owner of a Library. | |
178 class _LibraryOwner implements Indexable { | |
179 const _LibraryOwner(); | |
180 | |
181 String get docName => ''; | |
182 | |
183 bool get isPrivate => false; | |
184 | |
185 Indexable get owner => null; | |
186 | |
187 // This is a known incomplete implementation of Indexable | |
188 // overriding noSuchMethod to remove static warnings | |
189 noSuchMethod(Invocation invocation) { | |
190 throw new UnimplementedError(invocation.memberName.toString()); | |
191 } | |
192 } | |
OLD | NEW |