import { FileHelper } from "./../integration/file-helper" ; import * as glob from "glob" ; import * as RegExpEscape from "escape-string-regexp" ; export class PathFinder { private readonly regexPattern : RegExp = /((describe)|(it))\s*\(\s*((?<![\\])[\`\'\"])((?:.(?!(?<![\\])\4))*.?)\4/gi ; private readonly describeType = "describe" ; private readonly itType = "it" ; public constructor ( private readonly fileHelper ) { } public getTestFilesPaths ( pattern , encoding ) { const paths = { } ; const results = glob . sync ( pattern ) ; results . map ( ( path , index , array ) => { this . parseTestFile ( paths , path , this . getTestFileData ( path , encoding ) ) ; } ) ; return paths ; } public getSpecLine ( spec , path , encoding ) { const fileText = this . fileHelper . readFile ( path , encoding ) as any ; if ( ! fileText ) { return ; } return this . findLineContaining ( spec , fileText ) ; } public getTestFilePath ( paths , describe , it ) { const testFile = Object . keys ( paths ) . find ( path => this . exist ( paths , path , describe , it ) ) ; return testFile ; } private getTestFileData ( path , encoding ) { const fileText = this . fileHelper . readFile ( path , encoding ) ; return this . removeNewLines ( this . removeComments ( fileText ) ) ; } private parseTestFile ( paths , path , data ) { let result ; while ( ( result = this . regexPattern . exec ( data ) ) != null ) { const type = result [ 2 ] || result [ 3 ] ; const text = result [ 5 ] ; if ( paths [ path ] === undefined ) { paths [ path ] = { describe : [ ] , it : [ ] } ; } if ( type === this . describeType ) { paths [ path ] . describe . push ( text ) ; } if ( type === this . itType ) { paths [ path ] . it . push ( text ) ; } } } private exist ( paths , path , describe , it ) { const existsDescribe = paths [ path ] . describe . some ( ( element ) => describe . startsWith ( element ) ) ; const existsIt = paths [ path ] . it . some ( ( element ) => it . startsWith ( element ) ) ; return existsDescribe && existsIt ; } private removeComments ( data ) { return data . replace ( /\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm , "" ) ; } private removeNewLines ( data ) { return data . replace ( /\r?\n|\r/g , "" ) ; } private findLineContaining ( needle , haystack ) { if ( ! haystack ) { return undefined ; } const index = haystack . search ( RegExpEscape ( needle ) ) ; if ( index < 0 ) { return undefined ; } return haystack . substr ( 0 , index ) . split ( "\n" ) . length - 1 ; } }