import * as assert from 'assert' ; import * as fs from 'fs' ; import * as path from 'path' ; import { AnalyzerFileInfo } from '../analyzer/analyzerFileInfo' ; import { Binder } from '../analyzer/binder' ; import { ImportResolver } from '../analyzer/importResolver' ; import { Program } from '../analyzer/program' ; import { NameTypeWalker , TestWalker } from '../analyzer/testWalker' ; import { TypeEvaluator } from '../analyzer/typeEvaluatorTypes' ; import { cloneDiagnosticRuleSet , ConfigOptions , ExecutionEnvironment } from '../common/configOptions' ; import { fail } from '../common/debug' ; import { Diagnostic , DiagnosticCategory } from '../common/diagnostic' ; import { DiagnosticSink , TextRangeDiagnosticSink } from '../common/diagnosticSink' ; import { FullAccessHost } from '../common/fullAccessHost' ; import { createFromRealFileSystem } from '../common/realFileSystem' ; import { ParseOptions , Parser , ParseResults } from '../parser/parser' ; ( global as any ) . __rootDirectory = path . resolve ( ) ; export interface FileAnalysisResult { filePath : string ; parseResults ? : ParseResults | undefined ; errors : Diagnostic [ ] ; warnings : Diagnostic [ ] ; infos : Diagnostic [ ] ; unusedCodes : Diagnostic [ ] ; deprecateds : Diagnostic [ ] ; } export interface FileParseResult { fileContents : string ; parseResults : ParseResults ; } export function resolveSampleFilePath ( fileName ) { return path . resolve ( path . dirname ( module . filename ) , `./samples/${ fileName }` ) ; } export function readSampleFile ( fileName ) { const filePath = resolveSampleFilePath ( fileName ) ; try { return fs . readFileSync ( filePath , { encoding : 'utf8' } ) ; } catch { console . error ( `Could not read file "${ fileName }"` ) ; return '' ; } } export function parseText ( textToParse , diagSink , parseOptions = new ParseOptions ( ) ) { const parser = new Parser ( ) ; return parser . parseSourceFile ( textToParse , parseOptions , diagSink ) ; } export function parseSampleFile ( fileName , diagSink , execEnvironment = new ExecutionEnvironment ( '.' , undefined , undefined , undefined ) ) { const text = readSampleFile ( fileName ) ; const parseOptions = new ParseOptions ( ) ; if ( fileName . endsWith ( 'pyi' ) ) { parseOptions . isStubFile = true ; } parseOptions . pythonVersion = execEnvironment . pythonVersion ; return { fileContents : text , parseResults : parseText ( text , diagSink ) , } ; } export function buildAnalyzerFileInfo ( filePath , fileContents , parseResults , configOptions ) { const analysisDiagnostics = new TextRangeDiagnosticSink ( parseResults . tokenizerOutput . lines ) ; const fileInfo = { importLookup : ( _ ) => undefined , futureImports : new Map < string , boolean > ( ) , builtinsScope : undefined , diagnosticSink : analysisDiagnostics , executionEnvironment : configOptions . findExecEnvironment ( filePath ) , diagnosticRuleSet : cloneDiagnosticRuleSet ( configOptions . diagnosticRuleSet ) , fileContents , lines : parseResults . tokenizerOutput . lines , filePath , moduleName : '' , isStubFile : filePath . endsWith ( '.pyi' ) , isTypingStubFile : false , isInPyTypedPackage : false , isTypingExtensionsStubFile : false , isBuiltInStubFile : false , accessedSymbolMap : new Map < number , true > ( ) , } ; return fileInfo ; } export function bindSampleFile ( fileName , configOptions = new ConfigOptions ( '.' ) ) { const diagSink = new DiagnosticSink ( ) ; const filePath = resolveSampleFilePath ( fileName ) ; const execEnvironment = configOptions . findExecEnvironment ( filePath ) ; const parseInfo = parseSampleFile ( fileName , diagSink , execEnvironment ) ; const fileInfo = buildAnalyzerFileInfo ( filePath , parseInfo . fileContents , parseInfo . parseResults , configOptions ) ; const binder = new Binder ( fileInfo ) ; binder . bindModule ( parseInfo . parseResults . parseTree ) ; const testWalker = new TestWalker ( ) ; testWalker . walk ( parseInfo . parseResults . parseTree ) ; return { filePath , parseResults : parseInfo . parseResults , errors : fileInfo . diagnosticSink . getErrors ( ) , warnings : fileInfo . diagnosticSink . getWarnings ( ) , infos : fileInfo . diagnosticSink . getInformation ( ) , unusedCodes : fileInfo . diagnosticSink . getUnusedCode ( ) , deprecateds : fileInfo . diagnosticSink . getDeprecated ( ) , } ; } export function typeAnalyzeSampleFiles ( fileNames , configOptions = new ConfigOptions ( '.' ) ) { configOptions . internalTestMode = true ; const fs = createFromRealFileSystem ( ) ; const importResolver = new ImportResolver ( fs , configOptions , new FullAccessHost ( fs ) ) ; const program = new Program ( importResolver , configOptions ) ; const filePaths = fileNames . map ( ( name ) => resolveSampleFilePath ( name ) ) ; program . setTrackedFiles ( filePaths ) ; program . setPreCheckCallback ( ( parseResults , evaluator ) => { const nameTypeWalker = new NameTypeWalker ( evaluator ) ; nameTypeWalker . walk ( parseResults . parseTree ) ; } ) ; while ( program . analyze ( ) ) { } const sourceFiles = filePaths . map ( ( filePath ) => program . getSourceFile ( filePath ) ) ; return sourceFiles . map ( ( sourceFile , index ) => { if ( sourceFile ) { const diagnostics = sourceFile . getDiagnostics ( configOptions ) || [ ] ; const analysisResult = { filePath : sourceFile . getFilePath ( ) , parseResults : sourceFile . getParseResults ( ) , errors : diagnostics . filter ( ( diag ) => diag . category === DiagnosticCategory . Error ) , warnings : diagnostics . filter ( ( diag ) => diag . category === DiagnosticCategory . Warning ) , infos : diagnostics . filter ( ( diag ) => diag . category === DiagnosticCategory . Information ) , unusedCodes : diagnostics . filter ( ( diag ) => diag . category === DiagnosticCategory . UnusedCode ) , deprecateds : diagnostics . filter ( ( diag ) => diag . category === DiagnosticCategory . Deprecated ) , } ; return analysisResult ; } else { fail ( `Source file not found for ${ filePaths [ index ] }` ) ; const analysisResult = { filePath : '' , parseResults : undefined , errors : [ ] , warnings : [ ] , infos : [ ] , unusedCodes : [ ] , deprecateds : [ ] , } ; return analysisResult ; } } ) ; } export function printDiagnostics ( fileResults ) { if ( fileResults . errors . length > 0 ) { console . error ( `Errors in ${ fileResults . filePath }:` ) ; for ( const diag of fileResults . errors ) { console . error ( `  ${ diag . message }` ) ; } } if ( fileResults . warnings . length > 0 ) { console . error ( `Warnings in ${ fileResults . filePath }:` ) ; for ( const diag of fileResults . warnings ) { console . error ( `  ${ diag . message }` ) ; } } } export function validateResults ( results , errorCount , warningCount = 0 , infoCount ? , unusedCode ? , deprecated ? ) { assert . strictEqual ( results . length , 1 ) ; assert . strictEqual ( results [ 0 ] . errors . length , errorCount ) ; assert . strictEqual ( results [ 0 ] . warnings . length , warningCount ) ; if ( infoCount !== undefined ) { assert . strictEqual ( results [ 0 ] . infos . length , infoCount ) ; } if ( unusedCode !== undefined ) { assert . strictEqual ( results [ 0 ] . unusedCodes . length , unusedCode ) ; } if ( deprecated !== undefined ) { assert . strictEqual ( results [ 0 ] . deprecateds . length , deprecated ) ; } }