Example #1
0
        public async Task <CodeAnalysisResults> RunCodeAnalysisAsync(ISourceFile file,
                                                                     List <UnsavedFile> unsavedFiles, Func <bool> interruptRequested)
        {
            var result = new CodeAnalysisResults();

            var dataAssociation = GetAssociatedData(file);

            var currentUnsavedFile = unsavedFiles.FirstOrDefault(f => f.FileName == file.FilePath);
            var currentFileConts   = currentUnsavedFile?.Contents ?? File.ReadAllText(file.FilePath);
            var currentFileName    = currentUnsavedFile?.FileName ?? file.FilePath;
            TypeScriptSyntaxTree syntaxTree;
            // Only one analyzer at a time; the JS engine is single-threaded. TODO: Workaround with multiple JS engines
            await analysisThreadSemaphore.WaitAsync();

            try
            {
                syntaxTree = await _typeScriptContext.BuildAstAsync(currentFileName, currentFileConts);
            }
            catch (JavaScriptException)
            {
                return(new CodeAnalysisResults
                {
                    Diagnostics = new TextSegmentCollection <Diagnostic>
                    {
                        new Diagnostic
                        {
                            Project = file.Project,
                            Line = 1,
                            Spelling = "Code analysis language service call failed.",
                            StartOffset = 0,
                            File = file.Name,
                            Level = DiagnosticLevel.Error,
                        }
                    }
                });
            }
            finally
            {
                analysisThreadSemaphore.Release();
            }

#if DEBUG
            var syntaxTreeJsonDebug = JsonConvert.SerializeObject(syntaxTree);
#endif

            var lineCommentMatches = LineCommentPattern.Matches(currentFileConts);
            foreach (Match commentMatch in lineCommentMatches)
            {
                result.SyntaxHighlightingData.Add(new OffsetSyntaxHighlightingData
                {
                    Start  = commentMatch.Index,
                    Length = commentMatch.Length,
                    Type   = HighlightType.Comment
                });
            }

            var blockCommentMatches = BlockCommentPattern.Matches(currentFileConts);
            foreach (Match commentMatch in blockCommentMatches)
            {
                result.SyntaxHighlightingData.Add(new OffsetSyntaxHighlightingData
                {
                    Start  = commentMatch.Index,
                    Length = commentMatch.Length,
                    Type   = HighlightType.Comment
                });
            }

            // Highlight keywords
            var keywordMatches = KeywordPattern.Matches(currentFileConts);
            foreach (Match keywordMatch in keywordMatches)
            {
                result.SyntaxHighlightingData.Add(new OffsetSyntaxHighlightingData
                {
                    Start  = keywordMatch.Index,
                    Length = keywordMatch.Length,
                    Type   = HighlightType.Keyword
                });
            }

            // Recursively highlight and analyze from parse tree
            foreach (var rootStatement in syntaxTree.Statements)
            {
                HighlightNode(rootStatement, result);
            }

            // Diagnostics

            // Language service has diagnostics
            foreach (var diagnostic in syntaxTree.ParseDiagnostics)
            {
                // Convert diagnostics
                result.Diagnostics.Add(new Diagnostic
                {
                    Project     = file.Project,
                    Line        = GetLineNumber(currentFileConts, diagnostic.Start), // TODO
                    StartOffset = diagnostic.Start,
                    EndOffset   = diagnostic.Start + diagnostic.Length,
                    Spelling    = diagnostic.MessageText,
                    Level       = diagnostic.Category == TSBridge.Ast.Diagnostics.Diagnostic.DiagnosticCategory.Error
                        ? DiagnosticLevel.Error
                        : DiagnosticLevel.Warning
                });
            }

            result.Diagnostics.Add(new Diagnostic
            {
                Project     = file.Project,
                Line        = 1,
                Spelling    = "Code analysis for TypeScript is experimental and unstable. Use with caution.",
                StartOffset = 0,
                File        = file.Name,
                Level       = DiagnosticLevel.Warning,
            });

            return(result);
        }
        public async Task <CodeAnalysisResults> RunCodeAnalysisAsync(
            IEnumerable <UnsavedFile> unsavedFiles, Func <bool> interruptRequested)
        {
            var errorList   = IoC.Get <IErrorList>();
            var result      = new CodeAnalysisResults();
            var diagnostics = new List <Diagnostic>();

            var file            = _editor.SourceFile;
            var dataAssociation = GetAssociatedData(file);

            var currentUnsavedFile = unsavedFiles.FirstOrDefault(f => f.FileName == file.FilePath);
            var currentFileConts   = currentUnsavedFile?.Contents ?? File.ReadAllText(file.FilePath);
            var currentFileName    = currentUnsavedFile?.FileName ?? file.FilePath;
            TypeScriptSyntaxTree syntaxTree;
            // Only one analyzer at a time; the JS engine is single-threaded. TODO: Workaround with multiple JS engines
            await analysisThreadSemaphore.WaitAsync();

            try
            {
                syntaxTree = await _typeScriptContext.BuildAstAsync(currentFileName, currentFileConts);
            }
            catch (JavaScriptException)
            {
                diagnostics.Add(new Diagnostic(
                                    0, 0,
                                    _editor.SourceFile.Project.Name,
                                    _editor.SourceFile.Location,
                                    0,
                                    "Code analysis language service call failed.",
                                    "INT001",
                                    DiagnosticLevel.Error,
                                    DiagnosticCategory.Compiler));

                errorList.Remove((this, _editor.SourceFile));
                errorList.Create((this, _editor.SourceFile), null, DiagnosticSourceKind.Analysis, diagnostics.ToImmutableArray());

                return(new CodeAnalysisResults());
            }
            finally
            {
                analysisThreadSemaphore.Release();
            }

#if DEBUG
            var syntaxTreeJsonDebug = JsonConvert.SerializeObject(syntaxTree);
#endif

            var lineCommentMatches = LineCommentPattern.Matches(currentFileConts);
            foreach (Match commentMatch in lineCommentMatches)
            {
                result.SyntaxHighlightingData.Add(new OffsetSyntaxHighlightingData
                {
                    Start  = commentMatch.Index,
                    Length = commentMatch.Length,
                    Type   = HighlightType.Comment
                });
            }

            var blockCommentMatches = BlockCommentPattern.Matches(currentFileConts);
            foreach (Match commentMatch in blockCommentMatches)
            {
                result.SyntaxHighlightingData.Add(new OffsetSyntaxHighlightingData
                {
                    Start  = commentMatch.Index,
                    Length = commentMatch.Length,
                    Type   = HighlightType.Comment
                });
            }

            // Highlight keywords
            var keywordMatches = KeywordPattern.Matches(currentFileConts);
            foreach (Match keywordMatch in keywordMatches)
            {
                result.SyntaxHighlightingData.Add(new OffsetSyntaxHighlightingData
                {
                    Start  = keywordMatch.Index,
                    Length = keywordMatch.Length,
                    Type   = HighlightType.Keyword
                });
            }

            // Recursively highlight and analyze from parse tree
            foreach (var rootStatement in syntaxTree.Statements)
            {
                HighlightNode(rootStatement, result);
            }

            // Diagnostics
            foreach (var diagnostic in syntaxTree.ParseDiagnostics)
            {
                // Convert diagnostics
                diagnostics.Add(new Diagnostic(
                                    diagnostic.Start,
                                    diagnostic.Length,
                                    _editor.SourceFile.Project.Name,
                                    _editor.SourceFile.Location,
                                    GetLineNumber(currentFileConts, diagnostic.Start),
                                    diagnostic.MessageText,
                                    "INT002",
                                    diagnostic.Category == TSBridge.Ast.Diagnostics.Diagnostic.DiagnosticCategory.Error
                        ? DiagnosticLevel.Error
                        : DiagnosticLevel.Warning,
                                    DiagnosticCategory.Compiler
                                    ));
            }

            diagnostics.Add(new Diagnostic(
                                0,
                                0,
                                _editor.SourceFile.Project.Name,
                                _editor.SourceFile.Location,
                                0,
                                "Code analysis for TypeScript is experimental and unstable. Use with caution.",
                                "INT003",
                                DiagnosticLevel.Warning,
                                DiagnosticCategory.Compiler));

            errorList.Remove((this, _editor.SourceFile));
            errorList.Create((this, _editor.SourceFile), null, DiagnosticSourceKind.Analysis, diagnostics.ToImmutableArray());

            return(result);
        }