11import * as fs from 'fs'
2- import * as glob from 'glob'
3- import * as Path from 'path'
42import * as request from 'request-promise-native'
53import * as URI from 'urijs'
64import * as LSP from 'vscode-languageserver'
75import * as Parser from 'web-tree-sitter'
86
7+ import { getGlobPattern } from './config'
98import { uniqueBasedOnHash } from './util/array'
109import { flattenArray , flattenObjectValues } from './util/flatten'
10+ import { getFilePaths } from './util/fs'
1111import * as TreeSitterUtil from './util/tree-sitter'
1212
1313type Kinds = { [ type : string ] : LSP . SymbolKind }
@@ -27,10 +27,10 @@ export default class Analyzer {
2727 * Initialize the Analyzer based on a connection to the client and an optional
2828 * root path.
2929 *
30- * If the rootPath is provided it will initialize all *.sh files it can find
31- * anywhere on that path.
30+ * If the rootPath is provided it will initialize all shell files it can find
31+ * anywhere on that path. This non-exhaustive glob is used to preload the parser.
3232 */
33- public static fromRoot ( {
33+ public static async fromRoot ( {
3434 connection,
3535 rootPath,
3636 parser,
@@ -39,39 +39,37 @@ export default class Analyzer {
3939 rootPath : string | null
4040 parser : Parser
4141 } ) : Promise < Analyzer > {
42- // This happens if the users opens a single bash script without having the
43- // 'window' associated with a specific project.
44- if ( ! rootPath ) {
45- return Promise . resolve ( new Analyzer ( parser ) )
46- }
42+ const analyzer = new Analyzer ( parser )
43+
44+ if ( rootPath ) {
45+ const globPattern = getGlobPattern ( )
46+ connection . console . log (
47+ `Analyzing files matching glob "${ globPattern } " inside ${ rootPath } ` ,
48+ )
4749
48- return new Promise ( ( resolve , reject ) => {
49- glob ( '**/*.sh' , { cwd : rootPath } , ( err , paths ) => {
50- if ( err != null ) {
51- reject ( err )
52- } else {
53- const analyzer = new Analyzer ( parser )
54- paths . forEach ( p => {
55- const absolute = Path . join ( rootPath , p )
56- // only analyze files, glob pattern may match directories
57- if ( fs . existsSync ( absolute ) && fs . lstatSync ( absolute ) . isFile ( ) ) {
58- const uri = `file://${ absolute } `
59- connection . console . log ( `Analyzing ${ uri } ` )
60- analyzer . analyze (
61- uri ,
62- LSP . TextDocument . create (
63- uri ,
64- 'shell' ,
65- 1 ,
66- fs . readFileSync ( absolute , 'utf8' ) ,
67- ) ,
68- )
69- }
70- } )
71- resolve ( analyzer )
72- }
50+ const lookupStartTime = Date . now ( )
51+ const getTimePassed = ( ) : string =>
52+ `${ ( Date . now ( ) - lookupStartTime ) / 1000 } seconds`
53+
54+ // NOTE: An alternative would be to preload all files and analyze their
55+ // shebang or mimetype, but it would be fairly expensive.
56+ const filePaths = await getFilePaths ( { globPattern, rootPath } )
57+
58+ connection . console . log (
59+ `Glob resolved with ${ filePaths . length } files after ${ getTimePassed ( ) } ` ,
60+ )
61+
62+ filePaths . forEach ( filePath => {
63+ const uri = `file://${ filePath } `
64+ connection . console . log ( `Analyzing ${ uri } ` )
65+ const fileContent = fs . readFileSync ( filePath , 'utf8' )
66+ analyzer . analyze ( uri , LSP . TextDocument . create ( uri , 'shell' , 1 , fileContent ) )
7367 } )
74- } )
68+
69+ connection . console . log ( `Analyzer finished after ${ getTimePassed ( ) } ` )
70+ }
71+
72+ return analyzer
7573 }
7674
7775 private parser : Parser
0 commit comments