| 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 analyzer.source.embedder; | 5 library analyzer.source.embedder; |
| 6 | 6 |
| 7 import 'dart:collection' show HashMap; | 7 import 'dart:collection' show HashMap; |
| 8 import 'dart:core' hide Resource; | 8 import 'dart:core' hide Resource; |
| 9 | 9 |
| 10 import 'package:analyzer/file_system/file_system.dart'; | 10 import 'package:analyzer/file_system/file_system.dart'; |
| 11 import 'package:analyzer/src/context/context.dart'; |
| 12 import 'package:analyzer/src/generated/engine.dart'; |
| 13 import 'package:analyzer/src/generated/java_core.dart'; |
| 14 import 'package:analyzer/src/generated/java_engine.dart'; |
| 11 import 'package:analyzer/src/generated/java_io.dart' show JavaFile; | 15 import 'package:analyzer/src/generated/java_io.dart' show JavaFile; |
| 16 import 'package:analyzer/src/generated/sdk.dart'; |
| 12 import 'package:analyzer/src/generated/source.dart'; | 17 import 'package:analyzer/src/generated/source.dart'; |
| 13 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource; | 18 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource; |
| 14 import 'package:path/path.dart' as pathos; | 19 import 'package:path/path.dart' as pathos; |
| 15 import 'package:yaml/yaml.dart'; | 20 import 'package:yaml/yaml.dart'; |
| 16 | 21 |
| 22 const String _DART_COLON_PREFIX = 'dart:'; |
| 23 |
| 17 /// Given a packageMap, check in each package's lib directory for the | 24 /// Given a packageMap, check in each package's lib directory for the |
| 18 /// existence of an `_embedder.yaml` file. If the file contains a top level | 25 /// existence of an `_embedder.yaml` file. If the file contains a top level |
| 19 /// YamlMap, it will be added to the [embedderYamls] map. | 26 /// YamlMap, it will be added to the [embedderYamls] map. |
| 20 class EmbedderYamlLocator { | 27 class EmbedderYamlLocator { |
| 21 static const String EMBEDDER_FILE_NAME = '_embedder.yaml'; | 28 static const String EMBEDDER_FILE_NAME = '_embedder.yaml'; |
| 22 | 29 |
| 23 // Map from package's library directory to the parsed | 30 // Map from package's library directory to the parsed |
| 24 // YamlMap. | 31 // YamlMap. |
| 25 final Map<Folder, YamlMap> embedderYamls = new HashMap<Folder, YamlMap>(); | 32 final Map<Folder, YamlMap> embedderYamls = new HashMap<Folder, YamlMap>(); |
| 26 | 33 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 return; | 79 return; |
| 73 } | 80 } |
| 74 if (yaml is! YamlMap) { | 81 if (yaml is! YamlMap) { |
| 75 // TODO(pquitslund): Notify developer that something is wrong with the | 82 // TODO(pquitslund): Notify developer that something is wrong with the |
| 76 // _embedder.yaml file in libDir. | 83 // _embedder.yaml file in libDir. |
| 77 return; | 84 return; |
| 78 } | 85 } |
| 79 embedderYamls[libDir] = yaml; | 86 embedderYamls[libDir] = yaml; |
| 80 } | 87 } |
| 81 | 88 |
| 82 | |
| 83 /// Read the contents of [libDir]/[EMBEDDER_FILE_NAME] as a string. | 89 /// Read the contents of [libDir]/[EMBEDDER_FILE_NAME] as a string. |
| 84 /// Returns null if the file doesn't exist. | 90 /// Returns null if the file doesn't exist. |
| 85 String _readEmbedderYaml(Folder libDir) { | 91 String _readEmbedderYaml(Folder libDir) { |
| 86 File file = libDir.getChild(EMBEDDER_FILE_NAME); | 92 File file = libDir.getChild(EMBEDDER_FILE_NAME); |
| 87 try { | 93 try { |
| 88 return file.readAsStringSync(); | 94 return file.readAsStringSync(); |
| 89 } on FileSystemException { | 95 } on FileSystemException { |
| 90 // File can't be read. | 96 // File can't be read. |
| 91 return null; | 97 return null; |
| 92 } | 98 } |
| 93 } | 99 } |
| 94 } | 100 } |
| 95 | 101 |
| 96 /// Given the [embedderYamls] from [EmbedderYamlLocator] check each one for the | 102 /// Given the [embedderYamls] from [EmbedderYamlLocator] check each one for the |
| 97 /// top level key 'embedder_libs'. Under the 'embedder_libs' key are key value | 103 /// top level key 'embedder_libs'. Under the 'embedder_libs' key are key value |
| 98 /// pairs. Each key is a 'dart:' library uri and each value is a path | 104 /// pairs. Each key is a 'dart:' library uri and each value is a path |
| 99 /// (relative to the directory containing `_embedder.yaml`) to a dart script | 105 /// (relative to the directory containing `_embedder.yaml`) to a dart script |
| 100 /// for the given library. For example: | 106 /// for the given library. For example: |
| 101 /// | 107 /// |
| 102 /// embedder_libs: | 108 /// embedder_libs: |
| 103 /// 'dart:io': '../../sdk/io/io.dart' | 109 /// 'dart:io': '../../sdk/io/io.dart' |
| 104 /// | 110 /// |
| 105 /// If a key doesn't begin with `dart:` it is ignored. | 111 /// If a key doesn't begin with `dart:` it is ignored. |
| 106 /// | 112 /// |
| 107 class EmbedderUriResolver extends UriResolver { | 113 class EmbedderUriResolver extends DartUriResolver { |
| 108 static const String DART_COLON_PREFIX = 'dart:'; | |
| 109 | |
| 110 final Map<String, String> _urlMappings = <String, String>{}; | 114 final Map<String, String> _urlMappings = <String, String>{}; |
| 111 | 115 |
| 112 /// Construct a [EmbedderUriResolver] from a package map | 116 /// Construct a [EmbedderUriResolver] from a package map |
| 113 /// (see [PackageMapProvider]). | 117 /// (see [PackageMapProvider]). |
| 114 EmbedderUriResolver(Map<Folder, YamlMap> embedderYamls) { | 118 EmbedderUriResolver(Map<Folder, YamlMap> embedderYamls) |
| 119 : super(new _EmbedderSdk()) { |
| 120 (dartSdk as _EmbedderSdk)._resolver = this; |
| 115 if (embedderYamls == null) { | 121 if (embedderYamls == null) { |
| 116 return; | 122 return; |
| 117 } | 123 } |
| 118 embedderYamls.forEach(_processEmbedderYaml); | 124 embedderYamls.forEach(_processEmbedderYaml); |
| 119 } | 125 } |
| 120 | 126 |
| 121 void _processEmbedderYaml(Folder libDir, YamlMap map) { | 127 void _processEmbedderYaml(Folder libDir, YamlMap map) { |
| 122 YamlNode embedder_libs = map['embedder_libs']; | 128 YamlNode embedder_libs = map['embedder_libs']; |
| 123 if (embedder_libs == null) { | 129 if (embedder_libs == null) { |
| 124 return; | 130 return; |
| 125 } | 131 } |
| 126 if (embedder_libs is! YamlMap) { | 132 if (embedder_libs is! YamlMap) { |
| 127 return; | 133 return; |
| 128 } | 134 } |
| 129 (embedder_libs as YamlMap).forEach((k, v) => | 135 (embedder_libs as YamlMap) |
| 130 _processEmbedderLibs(k, v, libDir)); | 136 .forEach((k, v) => _processEmbedderLibs(k, v, libDir)); |
| 131 } | 137 } |
| 132 | 138 |
| 133 /// Install the mapping from [name] to [libDir]/[file]. | 139 /// Install the mapping from [name] to [libDir]/[file]. |
| 134 void _processEmbedderLibs(String name, String file, Folder libDir) { | 140 void _processEmbedderLibs(String name, String file, Folder libDir) { |
| 135 if (!name.startsWith(DART_COLON_PREFIX)) { | 141 if (!name.startsWith(_DART_COLON_PREFIX)) { |
| 136 // SDK libraries must begin with 'dart:'. | 142 // SDK libraries must begin with 'dart:'. |
| 137 // TODO(pquitslund): Notify developer that something is wrong with the | 143 // TODO(pquitslund): Notify developer that something is wrong with the |
| 138 // _embedder.yaml file in libDir. | 144 // _embedder.yaml file in libDir. |
| 139 return; | 145 return; |
| 140 } | 146 } |
| 141 String key = name; | 147 String key = name; |
| 142 String value = libDir.canonicalizePath(file); | 148 String value = libDir.canonicalizePath(file); |
| 143 _urlMappings[key] = value; | 149 _urlMappings[key] = value; |
| 150 String shortName = name.substring(_DART_COLON_PREFIX.length); |
| 151 SdkLibraryImpl library = new SdkLibraryImpl(shortName); |
| 152 library.path = value; |
| 153 (dartSdk as _EmbedderSdk)._librariesMap.setLibrary(name, library); |
| 144 } | 154 } |
| 145 | 155 |
| 146 /// Number of embedder libraries. | 156 /// Number of embedder libraries. |
| 147 int get length => _urlMappings.length; | 157 int get length => _urlMappings.length; |
| 148 | 158 |
| 149 /// Return the path mapping for [libName] or null if there is none. | 159 /// Return the path mapping for [libName] or null if there is none. |
| 150 String operator [](String libName) => _urlMappings[libName]; | 160 String operator [](String libName) => _urlMappings[libName]; |
| 151 | 161 |
| 152 @override | 162 @override |
| 153 Source resolveAbsolute(Uri importUri, [Uri actualUri]) { | 163 Source resolveAbsolute(Uri importUri, [Uri actualUri]) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 /// Resolve a 'part' statement inside an sdk extension. | 234 /// Resolve a 'part' statement inside an sdk extension. |
| 225 Source _resolvePart(Uri libraryEntry, String partPath, Uri importUri) { | 235 Source _resolvePart(Uri libraryEntry, String partPath, Uri importUri) { |
| 226 // Library part. | 236 // Library part. |
| 227 String directory = pathos.dirname(libraryEntry.path); | 237 String directory = pathos.dirname(libraryEntry.path); |
| 228 Uri partUri = new Uri.file(pathos.join(directory, partPath)); | 238 Uri partUri = new Uri.file(pathos.join(directory, partPath)); |
| 229 assert(partUri.isAbsolute); | 239 assert(partUri.isAbsolute); |
| 230 JavaFile javaFile = new JavaFile.fromUri(partUri); | 240 JavaFile javaFile = new JavaFile.fromUri(partUri); |
| 231 return new FileBasedSource(javaFile, importUri); | 241 return new FileBasedSource(javaFile, importUri); |
| 232 } | 242 } |
| 233 } | 243 } |
| 244 |
| 245 class _EmbedderSdk implements DartSdk { |
| 246 // TODO(danrubel) Refactor this with DirectoryBasedDartSdk |
| 247 |
| 248 /// The resolver associated with this embedder sdk. |
| 249 EmbedderUriResolver _resolver; |
| 250 |
| 251 /// The [AnalysisContext] which is used for all of the sources in this sdk. |
| 252 InternalAnalysisContext _analysisContext; |
| 253 |
| 254 /// The library map that is populated by visiting the AST structure parsed fro
m |
| 255 /// the contents of the libraries file. |
| 256 final LibraryMap _librariesMap = new LibraryMap(); |
| 257 |
| 258 @override |
| 259 AnalysisContext get context { |
| 260 if (_analysisContext == null) { |
| 261 _analysisContext = new SdkAnalysisContext(); |
| 262 SourceFactory factory = new SourceFactory([_resolver]); |
| 263 _analysisContext.sourceFactory = factory; |
| 264 List<String> uris = this.uris; |
| 265 ChangeSet changeSet = new ChangeSet(); |
| 266 for (String uri in uris) { |
| 267 changeSet.addedSource(factory.forUri(uri)); |
| 268 } |
| 269 _analysisContext.applyChanges(changeSet); |
| 270 } |
| 271 return _analysisContext; |
| 272 } |
| 273 |
| 274 @override |
| 275 List<SdkLibrary> get sdkLibraries => _librariesMap.sdkLibraries; |
| 276 |
| 277 // TODO(danrubel) Determine SDK version |
| 278 @override |
| 279 String get sdkVersion => '0'; |
| 280 |
| 281 @override |
| 282 List<String> get uris => _librariesMap.uris; |
| 283 |
| 284 @override |
| 285 Source fromFileUri(Uri uri) { |
| 286 JavaFile file = new JavaFile.fromUri(uri); |
| 287 String filePath = file.getAbsolutePath(); |
| 288 String srcPath = filePath.replaceAll('\\', '/'); |
| 289 |
| 290 String path; |
| 291 for (SdkLibrary library in _librariesMap.sdkLibraries) { |
| 292 String libraryPath = library.path; |
| 293 if (srcPath == libraryPath) { |
| 294 path = '$_DART_COLON_PREFIX${library.shortName}'; |
| 295 break; |
| 296 } |
| 297 } |
| 298 if (path == null) { |
| 299 for (SdkLibrary library in _librariesMap.sdkLibraries) { |
| 300 String libraryPath = library.path; |
| 301 int index = libraryPath.lastIndexOf('/'); |
| 302 if (index == -1) { |
| 303 continue; |
| 304 } |
| 305 String prefix = libraryPath.substring(0, index + 1); |
| 306 if (!srcPath.startsWith(prefix)) { |
| 307 continue; |
| 308 } |
| 309 var relPath = srcPath.substring(prefix.length); |
| 310 path = '$_DART_COLON_PREFIX${library.shortName}/$relPath'; |
| 311 break; |
| 312 } |
| 313 } |
| 314 |
| 315 if (path != null) { |
| 316 try { |
| 317 return new FileBasedSource(file, parseUriWithException(path)); |
| 318 } on URISyntaxException catch (exception, stackTrace) { |
| 319 AnalysisEngine.instance.logger.logInformation( |
| 320 "Failed to create URI: $path", |
| 321 new CaughtException(exception, stackTrace)); |
| 322 return null; |
| 323 } |
| 324 } |
| 325 return null; |
| 326 } |
| 327 |
| 328 @override |
| 329 SdkLibrary getSdkLibrary(String dartUri) => _librariesMap.getLibrary(dartUri); |
| 330 |
| 331 @override |
| 332 Source mapDartUri(String dartUri) { |
| 333 String libraryName; |
| 334 String relativePath; |
| 335 int index = dartUri.indexOf('/'); |
| 336 if (index >= 0) { |
| 337 libraryName = dartUri.substring(0, index); |
| 338 relativePath = dartUri.substring(index + 1); |
| 339 } else { |
| 340 libraryName = dartUri; |
| 341 relativePath = ""; |
| 342 } |
| 343 SdkLibrary library = getSdkLibrary(libraryName); |
| 344 if (library == null) { |
| 345 return null; |
| 346 } |
| 347 String srcPath; |
| 348 if (relativePath.isEmpty) { |
| 349 srcPath = library.path; |
| 350 } else { |
| 351 String libraryPath = library.path; |
| 352 int index = libraryPath.lastIndexOf('/'); |
| 353 if (index == -1) { |
| 354 return null; |
| 355 } |
| 356 String prefix = libraryPath.substring(0, index + 1); |
| 357 srcPath = '$prefix$relativePath'; |
| 358 } |
| 359 String filePath = srcPath.replaceAll('/', JavaFile.separator); |
| 360 try { |
| 361 JavaFile file = new JavaFile(filePath); |
| 362 return new FileBasedSource(file, parseUriWithException(dartUri)); |
| 363 } on URISyntaxException { |
| 364 return null; |
| 365 } |
| 366 } |
| 367 } |
| OLD | NEW |