package com.jetbrains.lang.dart.util; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PairConsumer; import com.jetbrains.lang.dart.ide.index.DartLibraryIndex; import com.jetbrains.lang.dart.sdk.DartSdk; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; public abstract class DartUrlResolver { public static final String DART_SCHEME = "dart"; public static final String DART_PREFIX = "dart:"; public static final String PACKAGE_SCHEME = "package"; public static final String PACKAGE_PREFIX = "package:"; public static final String FILE_SCHEME = "file"; public static final String FILE_PREFIX = "file:"; public static final String TEMP_SCHEME = "temp"; // TempFileSystem in tests only public static final String TEMP_PREFIX = "temp:"; // TempFileSystem in tests only public static final String PACKAGES_FOLDER_NAME = "packages"; public static final String DART_CORE_URI = "dart:core"; /** * Returned instance becomes obsolete if/when pubspec.yaml file is added or deleted or if module-specific custom package roots are changed, * so do not keep returned instance too long. * * @param project * @param contextFile may be pubspec.yaml file, its parent folder or any file/folder within this parent folder; in case of import statements resolve this must be an analyzed file * @return */ @NotNull public static DartUrlResolver getInstance(final @NotNull Project project, final @NotNull VirtualFile contextFile) { return new DartUrlResolverImpl(project, contextFile); } @Nullable public abstract VirtualFile getPubspecYamlFile(); /** * Process 'Path Packages' (https://www.dartlang.org/tools/pub/dependencies.html#path-packages) and this package itself (symlink to local 'lib' folder) */ public abstract void processLivePackages(final @NotNull PairConsumer<String, VirtualFile> packageNameAndDirConsumer); public abstract Collection<String> getLivePackageNames(); @Nullable public abstract VirtualFile getPackageDirIfNotInOldStylePackagesFolder(@NotNull final String packageName, @Nullable final String pathAfterPackageName); /** * Dart url has <code>dart:</code>, <code>package:</code> or <code>file:</code> scheme */ @Nullable public abstract VirtualFile findFileByDartUrl(@NotNull String url); @Nullable public static VirtualFile findFileInDartSdkLibFolder(final @NotNull Project project, final @Nullable DartSdk dartSdk, final @Nullable String dartUri) { if (dartSdk == null || dartUri == null || !dartUri.startsWith(DART_PREFIX)) return null; final int firstSlashIndex = dartUri.indexOf('/'); if (firstSlashIndex < 0) { // This is a main library file from SDK. For example "dart:html" URI maps to SDK/lib/html/dartium/html_dartium.dart file (according to info from SDK/lib/_internal/libraries.dart file) return DartLibraryIndex.getSdkLibByUri(project, dartUri); } // URI contains slash that means that this is a 'part'-file, for example "dart:_internal/symbol.dart". // First search for main library file ("dart:_internal" maps to SDK/lib/internal/internal.dart) and then look for its part near it. final String mainLibUri = dartUri.substring(0, firstSlashIndex); final VirtualFile mainLibFile = DartLibraryIndex.getSdkLibByUri(project, mainLibUri); if (mainLibFile != null) { final String partRelPath = dartUri.substring(firstSlashIndex + 1); final VirtualFile partFile = mainLibFile.getParent().findFileByRelativePath(partRelPath); if (partFile != null) { return partFile; } } // Finally look for file in SDK by its relative path final String sdkLibRelPath = dartUri.substring(DART_PREFIX.length()); final String path = dartSdk.getHomePath() + "/lib/" + sdkLibRelPath; return LocalFileSystem.getInstance().findFileByPath(path); } @NotNull public abstract String getDartUrlForFile(final @NotNull VirtualFile file); public boolean mayNeedDynamicUpdate() { return true; } }