OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library source.sdk_ext; | |
6 | |
7 import 'dart:convert'; | |
8 import 'dart:core' hide Resource; | |
9 | |
10 import 'package:analyzer/file_system/file_system.dart'; | |
11 import 'package:analyzer/src/generated/java_io.dart' show JavaFile; | |
12 import 'package:analyzer/src/generated/source.dart'; | |
13 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource; | |
14 import 'package:path/path.dart' as pathos; | |
15 | |
16 /// Given a packageMap (see [PackageMapProvider]), check in each package's lib | |
17 /// directory for the existence of a `_sdkext` file. This file must contain a | |
18 /// JSON encoded map. Each key in the map is a `dart:` library name. Each value | |
19 /// is a path (relative to the directory containing `_sdkext`) to a dart script | |
20 /// for the given library. For example: | |
21 /// { | |
22 /// "dart:sky": "../sdk_ext/dart_sky.dart" | |
23 /// } | |
24 /// | |
25 /// If a key doesn't begin with `dart:` it is ignored. | |
26 class SdkExtUriResolver extends UriResolver { | |
27 static const String SDK_EXT_NAME = '_sdkext'; | |
28 static const String DART_COLON_PREFIX = 'dart:'; | |
29 | |
30 final Map<String, String> _urlMappings = <String,String>{}; | |
31 | |
32 /// Construct a [SdkExtUriResolver] from a package map | |
33 /// (see [PackageMapProvider]). | |
34 SdkExtUriResolver(Map<String, List<Folder>> packageMap) { | |
35 if (packageMap == null) { | |
36 return; | |
37 } | |
38 packageMap.forEach(_processPackage); | |
39 } | |
40 | |
41 /// Number of sdk extensions. | |
42 int get length => _urlMappings.length; | |
43 | |
44 /// Return the path mapping for [libName] or null if there is none. | |
45 String operator[](String libName) => _urlMappings[libName]; | |
46 | |
47 /// Programmatically add a new SDK extension given a JSON description | |
48 /// ([sdkExtJSON]) and a lib directory ([libDir]). | |
49 void addSdkExt(String sdkExtJSON, Folder libDir) { | |
50 _processSdkExt(sdkExtJSON, libDir); | |
51 } | |
52 | |
53 @override | |
54 Source resolveAbsolute(Uri importUri) { | |
55 String libraryName = _libraryName(importUri); | |
56 String partPath = _partPath(importUri); | |
57 // Lookup library name in mappings. | |
58 String mapping = _urlMappings[libraryName]; | |
59 if (mapping == null) { | |
60 // Not found. | |
61 return null; | |
62 } | |
63 // This mapping points to the main entry file of the sdk extension. | |
64 Uri libraryEntry = new Uri.file(mapping); | |
65 if (!libraryEntry.isAbsolute) { | |
66 // We expect an absolute path. | |
67 return null; | |
68 } | |
69 | |
70 if (partPath != null) { | |
71 return _resolvePart(libraryEntry, partPath, importUri); | |
72 } else { | |
73 return _resolveEntry(libraryEntry, importUri); | |
74 } | |
75 } | |
76 | |
77 @override | |
78 Uri restoreAbsolute(Source source) { | |
79 String libraryName = _libraryName(source.uri); | |
80 if (_registeredSdkExtension(libraryName)) { | |
81 return source.uri; | |
82 } | |
83 return null; | |
84 } | |
85 | |
86 /// Return the library name of [importUri]. | |
87 String _libraryName(Uri importUri) { | |
88 var uri = importUri.toString(); | |
89 int index = uri.indexOf('/'); | |
90 if (index >= 0) { | |
91 return uri.substring(0, index); | |
92 } | |
93 return uri; | |
94 } | |
95 | |
96 /// Return the part path of [importUri]. | |
97 String _partPath(Uri importUri) { | |
98 var uri = importUri.toString(); | |
99 int index = uri.indexOf('/'); | |
100 if (index >= 0) { | |
101 return uri.substring(index + 1); | |
102 } | |
103 return null; | |
104 } | |
105 | |
106 /// Given a package [name] and a list of folders ([libDirs]), | |
107 /// add any found sdk extensions. | |
108 void _processPackage(String name, List<Folder> libDirs) { | |
109 for (var libDir in libDirs) { | |
110 var sdkExt = _readDotSdkExt(libDir); | |
111 if (sdkExt != null) { | |
112 _processSdkExt(sdkExt, libDir); | |
113 } | |
114 } | |
115 } | |
116 | |
117 /// Given the JSON for an SDK extension ([sdkExtJSON]) and a folder | |
118 /// ([libDir]), setup the uri mapping. | |
119 void _processSdkExt(String sdkExtJSON, Folder libDir) { | |
120 var sdkExt; | |
121 try { | |
122 sdkExt = JSON.decode(sdkExtJSON); | |
123 } catch (e) { | |
124 return; | |
125 } | |
126 if ((sdkExt == null) || (sdkExt is! Map)) { | |
127 return; | |
128 } | |
129 sdkExt.forEach((k, v) => _processSdkExtension(k, v, libDir)); | |
130 } | |
131 | |
132 /// Install the mapping from [name] to [libDir]/[file]. | |
133 void _processSdkExtension(String name, String file, Folder libDir) { | |
134 if (!name.startsWith(DART_COLON_PREFIX)) { | |
135 // SDK extensions must begin with 'dart:'. | |
136 return; | |
137 } | |
138 var key = name; | |
139 var value = libDir.canonicalizePath(file); | |
140 _urlMappings[key] = value; | |
141 } | |
142 | |
143 /// Read the contents of [libDir]/[SDK_EXT_NAME] as a string. | |
144 /// Returns null if the file doesn't exist. | |
145 String _readDotSdkExt(Folder libDir) { | |
146 var file = libDir.getChild(SDK_EXT_NAME); | |
147 try { | |
148 return file.readAsStringSync(); | |
149 } on FileSystemException { | |
150 // File can't be read. | |
151 return null; | |
152 } | |
153 } | |
154 | |
155 /// Returns true if [libraryName] is a registered sdk extension. | |
156 bool _registeredSdkExtension(String libraryName) { | |
157 return _urlMappings[libraryName] != null; | |
158 } | |
159 | |
160 /// Resolve an import of an sdk extension. | |
161 Source _resolveEntry(Uri libraryEntry, Uri importUri) { | |
162 // Library entry. | |
163 JavaFile javaFile = new JavaFile.fromUri(libraryEntry); | |
164 return new FileBasedSource(javaFile, importUri); | |
165 } | |
166 | |
167 /// Resolve a 'part' statement inside an sdk extension. | |
168 Source _resolvePart(Uri libraryEntry, String partPath, Uri importUri) { | |
169 // Library part. | |
170 var directory = pathos.dirname(libraryEntry.path); | |
171 var partUri = new Uri.file(pathos.join(directory, partPath)); | |
172 assert(partUri.isAbsolute); | |
173 JavaFile javaFile = new JavaFile.fromUri(partUri); | |
174 return new FileBasedSource(javaFile, importUri); | |
175 } | |
176 } | |
OLD | NEW |