11import glob from 'glob' ;
22import path from 'path' ;
3- import fs from 'fs/promises' ;
4- import fss from 'fs' ;
53import Cache from "vscode-rpgle/language/models/cache" ;
64import { IncludeStatement } from "vscode-rpgle/language/parserTypes" ;
75import { infoOut , warningOut } from './cli' ;
@@ -16,6 +14,7 @@ import { Logger } from './logger';
1614import { asPosix , getReferenceObjectsFrom , getSystemNameFromPath , toLocalPath } from './utils' ;
1715import { extCanBeProgram , getObjectType } from './builders/environment' ;
1816import { isSqlFunction } from './languages/sql' ;
17+ import { ReadFileSystem } from './readFileSystem' ;
1918
2019export type ObjectType = "PGM" | "SRVPGM" | "MODULE" | "FILE" | "BNDDIR" | "DTAARA" | "CMD" | "MENU" | "DTAQ" ;
2120
@@ -109,7 +108,7 @@ export class Targets {
109108
110109 public logger : Logger ;
111110
112- constructor ( private cwd : string ) {
111+ constructor ( private cwd : string , private fs : ReadFileSystem ) {
113112 this . rpgParser = setupParser ( this ) ;
114113 this . logger = new Logger ( ) ;
115114 }
@@ -138,7 +137,17 @@ export class Targets {
138137 this . resolvedObjects [ localPath ] = ileObject ;
139138 }
140139
141- public resolvePathToObject ( localPath : string , newText ?: string ) {
140+ public async loadProject ( withRef ?: string ) {
141+ if ( withRef ) {
142+ await this . handleRefsFile ( path . join ( this . cwd , withRef ) ) ;
143+ }
144+
145+ const initialFiles = await this . fs . getFiles ( this . cwd ) ;
146+ await this . loadObjectsFromPaths ( initialFiles ) ;
147+ await Promise . allSettled ( initialFiles . map ( f => this . parseFile ( f ) ) ) ;
148+ }
149+
150+ public async resolvePathToObject ( localPath : string , newText ?: string ) {
142151 if ( this . resolvedObjects [ localPath ] ) {
143152 if ( newText ) this . resolvedObjects [ localPath ] . text = newText ;
144153 return this . resolvedObjects [ localPath ] ;
@@ -163,7 +172,7 @@ export class Targets {
163172
164173 // If this file is an SQL file, we need to look to see if it has a long name as we need to resolve all names here
165174 if ( sqlExtensions . includes ( extension . toLowerCase ( ) ) ) {
166- const ref = this . sqlObjectDataFromPath ( localPath ) ;
175+ const ref = await this . sqlObjectDataFromPath ( localPath ) ;
167176 if ( ref ) {
168177 if ( ref . object . system ) theObject . systemName = ref . object . system . toUpperCase ( ) ;
169178 if ( ref . object . name ) theObject . longName = ref . object . name ;
@@ -190,17 +199,17 @@ export class Targets {
190199 * @param filePath Fully qualified path to the file. Assumed to exist.
191200 */
192201 public async handleRefsFile ( filePath : string ) {
193- const content = await fs . readFile ( filePath , { encoding : `utf-8` } ) ;
202+ const content = await this . fs . readFile ( filePath ) ;
194203
195204 const pseudoObjects = getReferenceObjectsFrom ( content ) ;
196205
197- pseudoObjects . forEach ( ileObject => {
206+ for ( const ileObject of pseudoObjects ) {
198207 if ( ! this . searchForObject ( ileObject ) ) {
199208 const key = `${ ileObject . systemName } .${ ileObject . type } ` ;
200209 ileObject . reference = true ;
201210 this . resolvedObjects [ key ] = ileObject ;
202211 }
203- } ) ;
212+ } ;
204213 }
205214
206215 public isReferenceObject ( ileObject : ILEObject , remove ?: boolean ) {
@@ -330,7 +339,7 @@ export class Targets {
330339
331340 public loadObjectsFromPaths ( paths : string [ ] ) {
332341 // optimiseFileList(paths); //Ensure we load SQL files first
333- paths . forEach ( p => this . resolvePathToObject ( p ) ) ;
342+ return Promise . all ( paths . map ( p => this . resolvePathToObject ( p ) ) ) ;
334343 }
335344
336345 public async parseFile ( filePath : string ) {
@@ -348,7 +357,7 @@ export class Targets {
348357 const ext = pathDetail . ext . substring ( 1 ) . toLowerCase ( ) ;
349358
350359 try {
351- const content = await fs . readFile ( filePath , { encoding : `utf-8` } ) ;
360+ const content = await this . fs . readFile ( filePath ) ;
352361 const eol = content . indexOf ( `\r\n` ) >= 0 ? `\r\n` : `\n` ;
353362
354363 // Really only applied to rpg
@@ -380,7 +389,8 @@ export class Targets {
380389 ) ;
381390
382391 if ( rpgDocs ) {
383- this . createRpgTarget ( filePath , rpgDocs , options ) ;
392+ const ileObject = await this . resolvePathToObject ( filePath , options . text ) ;
393+ this . createRpgTarget ( ileObject , filePath , rpgDocs , options ) ;
384394 }
385395
386396 }
@@ -391,13 +401,15 @@ export class Targets {
391401 const module = new Module ( ) ;
392402 module . parseStatements ( tokens ) ;
393403
394- this . createClTarget ( filePath , module , options ) ;
404+ const ileObject = await this . resolvePathToObject ( filePath ) ;
405+ this . createClTarget ( ileObject , filePath , module , options ) ;
395406 }
396407 else if ( ddsExtension . includes ( ext ) ) {
397408 const ddsFile = new dds ( ) ;
398409 ddsFile . parse ( content . split ( eol ) ) ;
399410
400- this . createDdsFileTarget ( filePath , ddsFile , options ) ;
411+ const ileObject = await this . resolvePathToObject ( filePath , options . text ) ;
412+ this . createDdsFileTarget ( ileObject , filePath , ddsFile , options ) ;
401413 }
402414 else if ( sqlExtensions . includes ( ext ) ) {
403415 const sqlDoc = new Document ( content ) ;
@@ -410,7 +422,8 @@ export class Targets {
410422 const module = new Module ( ) ;
411423 module . parseStatements ( tokens ) ;
412424
413- this . createSrvPgmTarget ( filePath , module , options ) ;
425+ const ileObject = await this . resolvePathToObject ( filePath , options . text ) ;
426+ this . createSrvPgmTarget ( ileObject , filePath , module , options ) ;
414427 }
415428 else if ( cmdExtensions . includes ( ext ) ) {
416429 this . createCmdTarget ( filePath , options ) ;
@@ -442,8 +455,7 @@ export class Targets {
442455 // Since cmd source doesn't explicity contains deps, we resolve later on
443456 }
444457
445- private createSrvPgmTarget ( localPath : string , module : Module , options : FileOptions = { } ) {
446- const ileObject = this . resolvePathToObject ( localPath , options . text ) ;
458+ private createSrvPgmTarget ( ileObject : ILEObject , localPath : string , module : Module , options : FileOptions = { } ) {
447459 const target : ILEObjectTarget = {
448460 ...ileObject ,
449461 deps : [ ] ,
@@ -515,8 +527,7 @@ export class Targets {
515527 /**
516528 * Handles all DDS types: pf, lf, dspf
517529 */
518- private createDdsFileTarget ( localPath : string , dds : dds , options : FileOptions = { } ) {
519- const ileObject = this . resolvePathToObject ( localPath , options . text ) ;
530+ private createDdsFileTarget ( ileObject : ILEObject , localPath : string , dds : dds , options : FileOptions = { } ) {
520531 const target : ILEObjectTarget = {
521532 ...ileObject ,
522533 deps : [ ]
@@ -610,10 +621,8 @@ export class Targets {
610621 this . addNewTarget ( target ) ;
611622 }
612623
613- private createClTarget ( localPath : string , module : Module , options : FileOptions = { } ) {
624+ private createClTarget ( ileObject : ILEObject , localPath : string , module : Module , options : FileOptions = { } ) {
614625 const pathDetail = path . parse ( localPath ) ;
615- const sourceName = pathDetail . base ;
616- const ileObject = this . resolvePathToObject ( localPath ) ;
617626 const target : ILEObjectTarget = {
618627 ...ileObject ,
619628 deps : [ ]
@@ -966,10 +975,8 @@ export class Targets {
966975 }
967976 }
968977
969- private createRpgTarget ( localPath : string , cache : Cache , options : FileOptions = { } ) {
978+ private createRpgTarget ( ileObject : ILEObject , localPath : string , cache : Cache , options : FileOptions = { } ) {
970979 const pathDetail = path . parse ( localPath ) ;
971- const ileObject = this . resolvePathToObject ( localPath , options . text ) ;
972-
973980 // define internal imports
974981 ileObject . imports = cache . procedures
975982 . filter ( ( proc : any ) => proc . keyword [ `EXTPROC` ] )
@@ -1380,9 +1387,9 @@ export class Targets {
13801387 this . createOrAppend ( bindingDirectoryTarget , target ) ;
13811388
13821389 // Make sure we can resolve to this service program
1383- target . exports . forEach ( e => {
1390+ for ( const e of target . exports ) {
13841391 this . resolvedExports [ e . toUpperCase ( ) ] = target ;
1385- } ) ;
1392+ }
13861393 } else {
13871394 // This service program target doesn't have any deps... so, it's not used?
13881395 this . removeObject ( target ) ;
@@ -1408,7 +1415,7 @@ export class Targets {
14081415 // Remove any service program deps so we can resolve them cleanly
14091416 currentTarget . deps = currentTarget . deps . filter ( d => ! [ `SRVPGM` ] . includes ( d . type ) ) ;
14101417
1411- currentTarget . imports . forEach ( importName => {
1418+ for ( const importName of currentTarget . imports ) {
14121419 // Find if this import resolves to another object
14131420 const possibleSrvPgmDep = this . resolvedExports [ importName . toUpperCase ( ) ] ;
14141421 // We can't add a module as a dependency at this step.
@@ -1430,7 +1437,7 @@ export class Targets {
14301437 }
14311438 }
14321439 }
1433- } ) ;
1440+ } ;
14341441
14351442 // If the program or module has imports that we ca resolve, then we add them as deps
14361443 if ( newImports . length > 0 ) {
@@ -1619,11 +1626,11 @@ export class Targets {
16191626 * Sadly the long name is not typically part of the path name, so we need to
16201627 * find the name inside of the source code.
16211628 */
1622- sqlObjectDataFromPath ( fullPath : string ) : ObjectRef | undefined {
1629+ async sqlObjectDataFromPath ( fullPath : string ) : Promise < ObjectRef > {
16231630 const relativePath = this . getRelative ( fullPath ) ;
16241631
1625- if ( fss . existsSync ( fullPath ) ) {
1626- const content = fss . readFileSync ( fullPath , { encoding : `utf-8` } ) ;
1632+ if ( await this . fs . exists ( fullPath ) ) {
1633+ const content = await this . fs . readFile ( fullPath ) ;
16271634 const document = new Document ( content ) ;
16281635
16291636 const groups = document . getStatementGroups ( ) ;
0 commit comments