Example #1
0
 public override bool IsCodeFile(string fileName)
 {
     var ext = Path.GetExtension(fileName);
     return StringComparer.OrdinalIgnoreCase.Equals(ext, NodejsConstants.JavaScriptExtension) ||
         StringComparer.OrdinalIgnoreCase.Equals(ext, NodejsConstants.JavaScriptJsxExtension) ||
         TypeScriptHelpers.IsTypeScriptFile(fileName);
 }
        internal bool IsTestFile(string pathToFile)
        {
            var testCaseFile = pathToFile;
            var project      = GetTestProjectFromFile(pathToFile);

            if (project == null)
            {
                //The file is not included in the project.
                //Don't look for tests in it.
                return(false);
            }

            //
            //Check to see if we are dealing with a TypeScript file
            //  If we are then switch the test container to the underlying js file
            //
            if (TypeScriptHelpers.IsTypeScriptFile(pathToFile))
            {
                var jsFile = TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(project, pathToFile);
                if (!File.Exists(jsFile))
                {
                    //Ignore the file for now.  On the next build event the typescript compiler will generate the file
                    //  at that point this function gets invoked again on the .ts file and we'll see the newly created .js file
                    return(false);
                }
            }
            else if (!StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(pathToFile), NodejsConstants.JavaScriptExtension))
            {
                return(false);
            }

            ErrorHandler.Succeeded(((IVsHierarchy)project).ParseCanonicalName(pathToFile, out var itemId));

            return(IsTestFile(itemId, project));
        }
        private bool ShouldDiscover(string pathToItem)
        {
            if (string.IsNullOrEmpty(pathToItem))
            {
                return(false);
            }

            if (pathToItem.IndexOf("\\node_modules\\", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                return(false);
            }

            //Setting/updating "TestFramework" property on a file item will cause metedata change in the project file,
            //so we need to re-discover when file change happens.
            if (TypeScriptHelpers.IsSupportedTestProjectFile(pathToItem))
            {
                return(true);
            }

            if (this.IsTestFile(pathToItem))
            {
                if (EqtTrace.IsVerboseEnabled)
                {
                    EqtTrace.Verbose("TestContainerDiscoverer: Found a test {0}.", pathToItem);
                }

                return(true);
            }

            return(false);
        }
Example #4
0
 public override CommonFileNode CreateCodeFileNode(ProjectElement item)
 {
     var fileName = item.Url;
     if (!string.IsNullOrWhiteSpace(fileName) && TypeScriptHelpers.IsTypeScriptFile(fileName))
     {
         return new NodejsTypeScriptFileNode(this, item);
     }
     return new NodejsFileNode(this, item);
 }
        private string ResolveStartupFile() {
            string startupFile = _project.GetStartupFile();
            if (string.IsNullOrEmpty(startupFile)) {
                throw new ApplicationException("Please select a startup file to launch by right-clicking the file in Solution Explorer and selecting 'Set as Node.js Startup File' or by modifying your configuration in project properties.");
            }

            if (TypeScriptHelpers.IsTypeScriptFile(startupFile)) {
                startupFile = TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(_project, startupFile);
            }
            return startupFile;
        }
Example #6
0
        public static bool TryGetProjectDirectory(this IVsProject project, out string path)
        {
            var succeeded = TryGetProjectPath(project, out path);

            if (succeeded && TypeScriptHelpers.IsSupportedTestProjectFile(path))
            {
                // remove project name from the path.
                path = Path.GetDirectoryName(path);
            }

            return(succeeded);
        }
        internal bool IsTestFile(string pathToFile)
        {
            var project = this.GetTestProjectFromFile(pathToFile);

            if (project == null)
            {
                //The file is not included in the project.
                //Don't look for tests in it.
                return(false);
            }

            //
            //Check to see if we are dealing with a TypeScript file
            //  If we are then switch the test container to the underlying js file
            //
            if (TypeScriptHelpers.IsTypeScriptFile(pathToFile))
            {
                var jsFile = TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(project, pathToFile);
                if (!File.Exists(jsFile))
                {
                    //Ignore the file for now.  On the next build event the typescript compiler will generate the file
                    //  at that point this function gets invoked again on the .ts file and we'll see the newly created .js file
                    return(false);
                }
            }
            else if (!StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(pathToFile), NodejsConstants.JavaScriptExtension))
            {
                return(false);
            }

            if (!(project is IVsBuildPropertyStorage propStore))
            {
                Debug.Fail($"Why is {nameof(project)} not of type {nameof(IVsBuildPropertyStorage)}?");

                return(false);
            }

            var hr = propStore.GetPropertyValue(NodeProjectProperty.TestRoot, /*configuration*/ "", (uint)_PersistStorageType.PST_PROJECT_FILE, out var testRoot);

            // if test root is specified check if the file is contained, otherwise fall back to old logic
            if (ErrorHandler.Succeeded(hr) && !string.IsNullOrEmpty(testRoot))
            {
                project.TryGetProjectPath(out var root);
                var testRootPath = Path.Combine(root, testRoot);

                return(CommonUtils.IsSubpathOf(root, pathToFile));
            }

            ErrorHandler.Succeeded(((IVsHierarchy)project).ParseCanonicalName(pathToFile, out var itemId));

            return(IsTestFile(itemId, project));
        }
Example #8
0
            protected override async Task <bool> IsValidFileAsync(string filePath)
            {
                // Only use the tsconfig.json determine the debug target when there is an outfile specified,
                // otherwise each .ts file can (in theory) be the entry point.
                if (TypeScriptHelpers.IsTsJsConfigJsonFile(filePath))
                {
                    var tsconfig = await TsConfigJsonFactory.CreateAsync(filePath);

                    return(!string.IsNullOrEmpty(tsconfig?.OutFile));
                }

                return(false);
            }
Example #9
0
        private static (string, string)? GetTestFrameworkAndFilePath(Project project, ProjectItem projectItem, string projectRoot)
        {
            var testRoot          = project.GetProperty(NodeProjectProperty.TestRoot)?.EvaluatedValue;
            var testFrameworkName = project.GetProperty(NodeProjectProperty.TestFramework)?.EvaluatedValue;

            string fileAbsolutePath;

            if (!string.IsNullOrEmpty(testRoot) && !string.IsNullOrEmpty(testFrameworkName)) // If the test root and framework have been configured on the project.
            {
                var testRootPath = Path.GetFullPath(Path.Combine(project.DirectoryPath, testRoot));

                try
                {
                    fileAbsolutePath = CommonUtils.GetAbsoluteFilePath(projectRoot, projectItem.EvaluatedInclude);
                }
                catch (ArgumentException)
                {
                    // .Net core projects include invalid paths, ignore them and continue checking the items.
                    return(null);
                }

                if (!fileAbsolutePath.StartsWith(testRootPath, StringComparison.OrdinalIgnoreCase))
                {
                    return(null);
                }
            }
            else // If the file has been configured individually.
            {
                testFrameworkName = projectItem.GetMetadataValue("TestFramework");
                if (!TestFramework.IsValidTestFramework(testFrameworkName))
                {
                    return(null);
                }
                fileAbsolutePath = CommonUtils.GetAbsoluteFilePath(projectRoot, projectItem.EvaluatedInclude);
            }

            // Check if file is a typecript file. If so, get the javascript file. The javascript file needs to be in the same path and name.
            // It doesn't work with bundlers or minimizers. Also, project needs to be build in order to have the js file created.
            var typeScriptTest = TypeScriptHelpers.IsTypeScriptFile(fileAbsolutePath);

            if (typeScriptTest)
            {
                fileAbsolutePath = TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(project, fileAbsolutePath);
            }
            else if (!StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(fileAbsolutePath), ".js"))
            {
                return(null);
            }

            return(testFrameworkName, fileAbsolutePath);
        }
Example #10
0
        private string ResolveStartupFile()
        {
            var startupFile = this._project.GetStartupFile();

            if (string.IsNullOrEmpty(startupFile))
            {
                throw new ApplicationException(Resources.DebugCouldNotResolveStartupFileErrorMessage);
            }

            if (TypeScriptHelpers.IsTypeScriptFile(startupFile))
            {
                startupFile = TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(this._project, startupFile);
            }
            return(startupFile);
        }
Example #11
0
        private string ResolveStartupFile()
        {
            string startupFile = _project.GetStartupFile();

            if (string.IsNullOrEmpty(startupFile))
            {
                throw new ApplicationException("No startup file is defined for the startup project.");
            }

            if (TypeScriptHelpers.IsTypeScriptFile(startupFile))
            {
                startupFile = TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(_project, startupFile);
            }
            return(startupFile);
        }
Example #12
0
        private IEnumerable <string> GetTestItems(string projectRoot, string outDir)
        {
            // TODO: Do our own directory traversal. It's better for performance.

            // If we find ts or tsx files, get the JS file and return.
            var files = Directory.EnumerateFiles(projectRoot, "*.ts?", SearchOption.AllDirectories)
                        .Where(x => !x.Contains("\\node_modules\\"));

            if (files.Any())
            {
                return(files
                       .Where(p => TypeScriptHelpers.IsTypeScriptFile(p))
                       .Select(p => TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(p, outDir, projectRoot)));
            }

            return(Directory.EnumerateFiles(projectRoot, "*.js", SearchOption.AllDirectories)
                   .Where(p => !p.Contains("\\node_modules\\")));
        }
            private async Task <bool> IsSupportedFileAsync(string filePath)
            {
                // config files are always good
                if (TypeScriptHelpers.IsTsJsConfigJsonFile(filePath))
                {
                    return(true);
                }

                // TypeScript files should only build when there is no containing config file
                if (TypeScriptHelpers.IsTypeScriptFile(filePath))
                {
                    if (await this.workspace.IsContainedByTsConfig(filePath) == null)
                    {
                        return(true);
                    }
                }

                return(false);
            }
        internal bool IsTestFile(string pathToFile)
        {
            var project = this.GetTestProjectFromFile(pathToFile);

            if (project == null)
            {
                //The file is not included in the project.
                //Don't look for tests in it.
                return(false);
            }

            //
            //Check to see if we are dealing with a TypeScript file
            //  If we are then switch the test container to the underlying js file
            //
            if (TypeScriptHelpers.IsTypeScriptFile(pathToFile))
            {
                var jsFile = TypeScriptHelpers.GetTypeScriptBackedJavaScriptFile(project, pathToFile);
                if (jsFile == null || !File.Exists(jsFile))
                {
                    //Ignore the file for now.  On the next build event the typescript compiler will generate the file
                    //  at that point this function gets invoked again on the .ts file and we'll see the newly created .js file
                    return(false);
                }
            }
            else if (!TypeScriptHelpers.IsJavaScriptFile(pathToFile))
            {
                return(false);
            }

            if (TryGetProjectUnitTestProperties(project, out var testRoot, out _) &&
                !string.IsNullOrEmpty(testRoot) &&
                project.TryGetProjectDirectory(out var root))
            {
                var testRootPath = Path.Combine(root, testRoot);

                return(CommonUtils.IsSubpathOf(testRootPath, pathToFile));
            }

            ErrorHandler.Succeeded(((IVsHierarchy)project).ParseCanonicalName(pathToFile, out var itemId));

            return(IsTestFile(itemId, project));
        }
Example #15
0
        internal override string GetItemType(string filename)
        {
            var absFileName =
                Path.IsPathRooted(filename) ?
                filename :
                Path.Combine(this.ProjectHome, filename);

            var node = this.FindNodeByFullPath(absFileName) as NodejsFileNode;
            if (node?.ItemNode?.ItemTypeName != null)
            {
                return node.ItemNode.ItemTypeName;
            }

            if (TypeScriptHelpers.IsTypeScriptFile(filename))
            {
                return NodejsConstants.TypeScriptCompileItemType;
            }
            return base.GetItemType(filename);
        }
        public IEnumerable <ITestContainer> GetTestContainers(IVsProject project)
        {
            if (!project.TryGetProjectPath(out var path))
            {
                yield break;
            }

            // No need to search for tests in not supported projects.
            if (!TypeScriptHelpers.IsSupportedTestProjectFile(path))
            {
                yield break;
            }

            if (this.detectingChanges)
            {
                this.SaveModifiedFiles(project);
            }

            if (!this.knownProjects.TryGetValue(path, out var projectInfo) || !TryGetProjectUnitTestProperties(projectInfo.Project, out _, out _))
            {
                // Don't return any containers for projects we don't know about or that we know that they are not configured for JavaScript unit tests.
                yield break;
            }
            projectInfo.HasRequestedContainers = true;

            var latestWrite = project.GetProjectItemPaths().Aggregate(
                this.lastWrite,
                (latest, filePath) =>
            {
                try
                {
                    var ft = File.GetLastWriteTimeUtc(filePath);
                    return((ft > latest) ? ft : latest);
                }
                catch (Exception exc) when(exc is UnauthorizedAccessException || exc is ArgumentException || exc is IOException)
                {
                }
                return(latest);
            });

            yield return(new TestContainer(this, path, latestWrite));
        }
Example #17
0
        public static async Task <TsConfigJson> IsContainedByTsConfig(this IWorkspace workspace, string filePath)
        {
            var fileService = workspace.GetFindFilesService();
            var collector   = new FileCollector();
            await fileService.FindFilesAsync("sconfig.json", collector);

            foreach (var configFile in collector.FoundFiles)
            {
                if (TypeScriptHelpers.IsTsJsConfigJsonFile(configFile))
                {
                    var directory = Path.GetDirectoryName(configFile);
                    if (filePath.StartsWith(directory, StringComparison.OrdinalIgnoreCase))
                    {
                        return(await TsConfigJsonFactory.CreateAsync(configFile));
                    }
                }
            }

            return(null);
        }
Example #18
0
        internal override string GetItemType(string filename)
        {
            var absFileName =
                Path.IsPathRooted(filename) ?
                filename :
                Path.Combine(this.ProjectHome, filename);

            var node = this.FindNodeByFullPath(absFileName) as NodejsFileNode;

            if (node?.ItemNode?.ItemTypeName != null)
            {
                return(node.ItemNode.ItemTypeName);
            }

            // We need to return TypeScriptCompile for now to maintain backwards compatibility. In the future we will return "None" once the TypeScript SDK has been removed.
            if (TypeScriptHelpers.IsTypeScriptFile(filename))
            {
                return(NodejsConstants.TypeScriptCompileItemType);
            }

            return(base.GetItemType(filename));
        }
            public async Task <IReadOnlyList <IFileContextAction> > GetActionsAsync(string filePath, FileContext fileContext, CancellationToken cancellationToken)
            {
                await this.workspaceContext.JTF.SwitchToMainThreadAsync();

                this.outputPane.InitializeOutputPanes();

                var actions = new List <IFileContextAction>();

                if (TypeScriptHelpers.IsTsJsConfigJsonFile(filePath))
                {
                    actions.Add(new BuildTsConfigContextAction(filePath, fileContext, this.outputPane));
                }
                else if (TypeScriptHelpers.IsTypeScriptFile(filePath))
                {
                    var tsconfig = await this.workspaceContext.IsContainedByTsConfig(filePath);

                    if (tsconfig == null)
                    {
                        actions.Add(new BuildTsFileContextAction(filePath, fileContext, this.outputPane));
                    }
                }

                return(actions);
            }
Example #20
0
 private static bool IsProjectTypeScriptSourceFile(string path)
 {
     return(TypeScriptHelpers.IsTypeScriptFile(path) &&
            !StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(path), NodejsConstants.TypeScriptDeclarationExtension) &&
            !NodejsConstants.ContainsNodeModulesOrBowerComponentsFolder(path));
 }
 private static bool IsSupportedFile(string filePath)
 {
     return(TypeScriptHelpers.IsTypeScriptFile(filePath) || TypeScriptHelpers.IsTsJsConfigJsonFile(filePath));
 }
Example #22
0
            protected override Task <bool> IsValidFileAsync(string filePath)
            {
                var isValidFile = TypeScriptHelpers.IsTypeScriptFile(filePath);

                return(Task.FromResult(isValidFile));
            }
Example #23
0
        internal static void WriteProjectXml(
            XmlWriter writer,
            string projectPath,
            string sourcePath,
            string filters,
            string startupFile,
            string typeScriptVersion,
            ProjectLanguage projectLanguage
            )
        {
            var projectHome = CommonUtils.GetRelativeDirectoryPath(Path.GetDirectoryName(projectPath), sourcePath);
            var projectGuid = Guid.NewGuid();

            writer.WriteStartDocument();
            writer.WriteStartElement("Project", "http://schemas.microsoft.com/developer/msbuild/2003");
            writer.WriteAttributeString("DefaultTargets", "Build");

            writer.WriteStartElement("PropertyGroup");

            writer.WriteStartElement("Configuration");
            writer.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
            writer.WriteString("Debug");
            writer.WriteEndElement();

            writer.WriteElementString("SchemaVersion", "2.0");
            writer.WriteElementString("ProjectGuid", projectGuid.ToString("B"));
            writer.WriteElementString("ProjectHome", string.IsNullOrWhiteSpace(projectHome) ? "." : projectHome);
            writer.WriteElementString("ProjectView", "ShowAllFiles");

            if (CommonUtils.IsValidPath(startupFile))
            {
                writer.WriteElementString("StartupFile", Path.GetFileName(startupFile));
            }
            else
            {
                writer.WriteElementString("StartupFile", string.Empty);
            }
            writer.WriteElementString("WorkingDirectory", ".");
            writer.WriteElementString("OutputPath", ".");
            writer.WriteElementString("ProjectTypeGuids", "{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}");

            var typeScriptSupport = projectLanguage == ProjectLanguage.TypeScript || filters.IndexOf("*.ts", StringComparison.OrdinalIgnoreCase) > -1;

            if (typeScriptSupport)
            {
                writer.WriteElementString("TypeScriptSourceMap", "true");
                writer.WriteElementString("TypeScriptModuleKind", "CommonJS");
                writer.WriteElementString("EnableTypeScript", "true");
                if (typeScriptVersion != null)
                {
                    writer.WriteElementString("TypeScriptToolsVersion", typeScriptVersion);
                }
            }

            writer.WriteStartElement("VisualStudioVersion");
            writer.WriteAttributeString("Condition", "'$(VisualStudioVersion)' == ''");
            writer.WriteString("14.0");
            writer.WriteEndElement();

            writer.WriteStartElement("VSToolsPath");
            writer.WriteAttributeString("Condition", "'$(VSToolsPath)' == ''");
            writer.WriteString(@"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)");
            writer.WriteEndElement();

            writer.WriteEndElement(); // </PropertyGroup>

            // VS requires property groups with conditions for Debug
            // and Release configurations or many COMExceptions are
            // thrown.
            writer.WriteStartElement("PropertyGroup");
            writer.WriteAttributeString("Condition", "'$(Configuration)' == 'Debug'");
            writer.WriteEndElement();
            writer.WriteStartElement("PropertyGroup");
            writer.WriteAttributeString("Condition", "'$(Configuration)' == 'Release'");
            writer.WriteEndElement();

            var folders = new HashSet <string>(
                Directory.EnumerateDirectories(sourcePath, "*", SearchOption.AllDirectories)
                .Select(dirName =>
                        CommonUtils.TrimEndSeparator(
                            CommonUtils.GetRelativeDirectoryPath(sourcePath, dirName)
                            )
                        )
                .Where(ShouldIncludeDirectory)
                );

            // Exclude node_modules and bower_components folders.
            folders.RemoveWhere(NodejsConstants.ContainsNodeModulesOrBowerComponentsFolder);

            writer.WriteStartElement("ItemGroup");

            var projectFileFilters = "";

            switch (projectLanguage)
            {
            case ProjectLanguage.TypeScript:
                projectFileFilters = filters + TypeScriptFilters;
                break;

            case ProjectLanguage.JavaScript:
            default:
                projectFileFilters = filters + JavaScriptFilters;
                break;
            }

            foreach (var file in EnumerateAllFiles(sourcePath, projectFileFilters, projectLanguage))
            {
                if (TypeScriptHelpers.IsTypeScriptFile(file))
                {
                    writer.WriteStartElement("TypeScriptCompile");
                }
                else
                {
                    writer.WriteStartElement("Content");
                }
                writer.WriteAttributeString("Include", file);
                writer.WriteEndElement();
            }
            writer.WriteEndElement();

            writer.WriteStartElement("ItemGroup");
            foreach (var folder in folders.Where(s => !string.IsNullOrWhiteSpace(s)).OrderBy(s => s))
            {
                writer.WriteStartElement("Folder");
                writer.WriteAttributeString("Include", folder);
                writer.WriteEndElement();
            }
            writer.WriteEndElement();

            writer.WriteStartElement("Import");
            writer.WriteAttributeString("Project", @"$(MSBuildToolsPath)\Microsoft.Common.targets");
            writer.WriteAttributeString("Condition", @"Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')");
            writer.WriteEndElement();

            writer.WriteComment("Do not delete the following Import Project.  While this appears to do nothing it is a marker for setting TypeScript properties before our import that depends on them.");
            writer.WriteStartElement("Import");
            writer.WriteAttributeString("Project", @"$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets");
            writer.WriteAttributeString("Condition", @"False");
            writer.WriteEndElement();

            writer.WriteStartElement("Import");
            writer.WriteAttributeString("Project", @"$(VSToolsPath)\Node.js Tools\Microsoft.NodejsTools.targets");
            writer.WriteEndElement();

            writer.WriteRaw(@"
    <ProjectExtensions>
        <VisualStudio>
          <FlavorProperties GUID=""{349c5851-65df-11da-9384-00065b846f21}"">
            <WebProjectProperties>
              <UseIIS>False</UseIIS>
              <AutoAssignPort>True</AutoAssignPort>
              <DevelopmentServerPort>0</DevelopmentServerPort>
              <DevelopmentServerVPath>/</DevelopmentServerVPath>
              <IISUrl>http://localhost:48022/</IISUrl>
              <NTLMAuthentication>False</NTLMAuthentication>
              <UseCustomServer>True</UseCustomServer>
              <CustomServerUrl>http://localhost:1337</CustomServerUrl>
              <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
            </WebProjectProperties>
          </FlavorProperties>
          <FlavorProperties GUID=""{349c5851-65df-11da-9384-00065b846f21}"" User="""">
            <WebProjectProperties>
              <StartPageUrl>
              </StartPageUrl>
              <StartAction>CurrentPage</StartAction>
              <AspNetDebugging>True</AspNetDebugging>
              <SilverlightDebugging>False</SilverlightDebugging>
              <NativeDebugging>False</NativeDebugging>
              <SQLDebugging>False</SQLDebugging>
              <ExternalProgram>
              </ExternalProgram>
              <StartExternalURL>
              </StartExternalURL>
              <StartCmdLineArguments>
              </StartCmdLineArguments>
              <StartWorkingDirectory>
              </StartWorkingDirectory>
              <EnableENC>False</EnableENC>
              <AlwaysStartWebServerOnDebug>False</AlwaysStartWebServerOnDebug>
            </WebProjectProperties>
          </FlavorProperties>
        </VisualStudio>
    </ProjectExtensions>
");

            writer.WriteEndElement(); // </Project>

            writer.WriteEndDocument();
        }
 protected override Task <bool> IsValidFileAsync(string filePath)
 {
     return(Task.FromResult(TypeScriptHelpers.IsTsJsConfigJsonFile(filePath)));
 }