// 'parentItem' can be either a Project or ProjectItem private static async Task <EnvDTE.ProjectItem> GetOrCreateFolderAsync( EnvDTE.Project envDTEProject, object parentItem, string fullPath, string folderRelativePath, string folderName, bool createIfNotExists) { Debug.Assert(ThreadHelper.CheckAccess()); if (parentItem == null) { return(null); } EnvDTE.ProjectItem subFolder; EnvDTE.ProjectItems envDTEProjectItems = GetProjectItems(parentItem); if (TryGetFolder(envDTEProjectItems, folderName, out subFolder)) { // Get the sub folder return(subFolder); } if (createIfNotExists) { // The JS Metro project system has a bug whereby calling AddFolder() to an existing folder that // does not belong to the project will throw. To work around that, we have to manually include // it into our project. if (EnvDTEProjectInfoUtility.IsJavaScriptProject(envDTEProject) && Directory.Exists(fullPath)) { bool succeeded = await IncludeExistingFolderToProjectAsync(envDTEProject, folderRelativePath); if (succeeded) { // IMPORTANT: after including the folder into project, we need to get // a new EnvDTEProjecItems snapshot from the parent item. Otherwise, reusing // the old snapshot from above won't have access to the added folder. envDTEProjectItems = GetProjectItems(parentItem); if (TryGetFolder(envDTEProjectItems, folderName, out subFolder)) { // Get the sub folder return(subFolder); } } return(null); } try { return(envDTEProjectItems.AddFromDirectory(fullPath)); } catch (NotImplementedException) { // This is the case for F#'s project system, we can't add from directory so we fall back // to this impl return(envDTEProjectItems.AddFolder(folderName)); } } return(null); }