@@ -22,7 +22,7 @@ import { BuildFlags } from "./toolchain/BuildFlags";
2222import { SwiftOutputChannel } from "./ui/SwiftOutputChannel" ;
2323
2424/** Swift Package Manager contents */
25- export interface PackageContents {
25+ interface PackageContents {
2626 name : string ;
2727 products : Product [ ] ;
2828 dependencies : Dependency [ ] ;
@@ -185,8 +185,10 @@ function isError(state: SwiftPackageState): state is Error {
185185/**
186186 * Class holding Swift Package Manager Package
187187 */
188- export class SwiftPackage implements PackageContents {
188+ export class SwiftPackage {
189189 public plugins : PackagePlugin [ ] = [ ] ;
190+ private _contents : SwiftPackageState | undefined ;
191+
190192 /**
191193 * SwiftPackage Constructor
192194 * @param folder folder package is in
@@ -195,7 +197,7 @@ export class SwiftPackage implements PackageContents {
195197 */
196198 private constructor (
197199 readonly folder : vscode . Uri ,
198- private contents : SwiftPackageState ,
200+ private contentsPromise : Promise < SwiftPackageState > ,
199201 public resolved : PackageResolved | undefined ,
200202 private workspaceState : WorkspaceState | undefined
201203 ) { }
@@ -209,10 +211,34 @@ export class SwiftPackage implements PackageContents {
209211 folder : vscode . Uri ,
210212 toolchain : SwiftToolchain
211213 ) : Promise < SwiftPackage > {
212- const contents = await SwiftPackage . loadPackage ( folder , toolchain ) ;
213- const resolved = await SwiftPackage . loadPackageResolved ( folder ) ;
214- const workspaceState = await SwiftPackage . loadWorkspaceState ( folder ) ;
215- return new SwiftPackage ( folder , contents , resolved , workspaceState ) ;
214+ const [ resolved , workspaceState ] = await Promise . all ( [
215+ SwiftPackage . loadPackageResolved ( folder ) ,
216+ SwiftPackage . loadWorkspaceState ( folder ) ,
217+ ] ) ;
218+ return new SwiftPackage (
219+ folder ,
220+ SwiftPackage . loadPackage ( folder , toolchain ) ,
221+ resolved ,
222+ workspaceState
223+ ) ;
224+ }
225+
226+ /**
227+ * Returns the package state once it has loaded.
228+ * A snapshot of the state is stored in `_contents` after initial resolution.
229+ */
230+ private get contents ( ) : Promise < SwiftPackageState > {
231+ return this . contentsPromise . then ( contents => {
232+ // If `reload` is called immediately its possible for it to resolve
233+ // before the initial contentsPromise resolution. In that case return
234+ // the newer loaded `_contents`.
235+ if ( this . _contents === undefined ) {
236+ this . _contents = contents ;
237+ return contents ;
238+ } else {
239+ return this . _contents ;
240+ }
241+ } ) ;
216242 }
217243
218244 /**
@@ -329,7 +355,9 @@ export class SwiftPackage implements PackageContents {
329355
330356 /** Reload swift package */
331357 public async reload ( toolchain : SwiftToolchain ) {
332- this . contents = await SwiftPackage . loadPackage ( this . folder , toolchain ) ;
358+ const loadedContents = await SwiftPackage . loadPackage ( this . folder , toolchain ) ;
359+ this . _contents = loadedContents ;
360+ this . contentsPromise = Promise . resolve ( loadedContents ) ;
333361 }
334362
335363 /** Reload Package.resolved file */
@@ -346,31 +374,26 @@ export class SwiftPackage implements PackageContents {
346374 }
347375
348376 /** Return if has valid contents */
349- public get isValid ( ) : boolean {
350- return isPackage ( this . contents ) ;
377+ public get isValid ( ) : Promise < boolean > {
378+ return this . contents . then ( contents => isPackage ( contents ) ) ;
351379 }
352380
353381 /** Load error */
354- public get error ( ) : Error | undefined {
355- if ( isError ( this . contents ) ) {
356- return this . contents ;
357- } else {
358- return undefined ;
359- }
382+ public get error ( ) : Promise < Error | undefined > {
383+ return this . contents . then ( contents => ( isError ( contents ) ? contents : undefined ) ) ;
360384 }
361385
362386 /** Did we find a Package.swift */
363- public get foundPackage ( ) : boolean {
364- return this . contents !== undefined ;
387+ public get foundPackage ( ) : Promise < boolean > {
388+ return this . contents . then ( contents => contents !== undefined ) ;
365389 }
366390
367- public rootDependencies ( ) : ResolvedDependency [ ] {
391+ public get rootDependencies ( ) : Promise < ResolvedDependency [ ] > {
368392 // Correlate the root dependencies found in the Package.swift with their
369393 // checked out versions in the workspace-state.json.
370- const result = this . dependencies . map ( dependency =>
371- this . resolveDependencyAgainstWorkspaceState ( dependency )
394+ return this . dependencies . then ( dependencies =>
395+ dependencies . map ( dependency => this . resolveDependencyAgainstWorkspaceState ( dependency ) )
372396 ) ;
373- return result ;
374397 }
375398
376399 private resolveDependencyAgainstWorkspaceState ( dependency : Dependency ) : ResolvedDependency {
@@ -446,55 +469,70 @@ export class SwiftPackage implements PackageContents {
446469 }
447470 }
448471
449- /** name of Swift Package */
450- get name ( ) : string {
451- return ( this . contents as PackageContents ) ?. name ?? "" ;
472+ /** getName of Swift Package */
473+ get name ( ) : Promise < string > {
474+ return this . contents . then ( contents => ( contents as PackageContents ) ?. name ?? "" ) ;
452475 }
453476
454477 /** array of products in Swift Package */
455- get products ( ) : Product [ ] {
456- return ( this . contents as PackageContents ) ?. products ?? [ ] ;
478+ private get products ( ) : Promise < Product [ ] > {
479+ return this . contents . then ( contents => ( contents as PackageContents ) ?. products ?? [ ] ) ;
457480 }
458481
459482 /** array of dependencies in Swift Package */
460- get dependencies ( ) : Dependency [ ] {
461- return ( this . contents as PackageContents ) ?. dependencies ?? [ ] ;
483+ get dependencies ( ) : Promise < Dependency [ ] > {
484+ return this . contents . then ( contents => ( contents as PackageContents ) ?. dependencies ?? [ ] ) ;
462485 }
463486
464487 /** array of targets in Swift Package */
465- get targets ( ) : Target [ ] {
466- return ( this . contents as PackageContents ) ?. targets ?? [ ] ;
488+ get targets ( ) : Promise < Target [ ] > {
489+ return this . contents . then ( contents => ( contents as PackageContents ) ?. targets ?? [ ] ) ;
467490 }
468491
469492 /** array of executable products in Swift Package */
470- get executableProducts ( ) : Product [ ] {
471- return this . products . filter ( product => product . type . executable !== undefined ) ;
493+ get executableProducts ( ) : Promise < Product [ ] > {
494+ return this . products . then ( products =>
495+ products . filter ( product => product . type . executable !== undefined )
496+ ) ;
472497 }
473498
474499 /** array of library products in Swift Package */
475- get libraryProducts ( ) : Product [ ] {
476- return this . products . filter ( product => product . type . library !== undefined ) ;
500+ get libraryProducts ( ) : Promise < Product [ ] > {
501+ return this . products . then ( products =>
502+ products . filter ( product => product . type . library !== undefined )
503+ ) ;
504+ }
505+
506+ /**
507+ * Array of targets in Swift Package. The targets may not be loaded yet.
508+ * It is preferable to use the `targets` property that returns a promise that
509+ * returns the targets when they're guarenteed to be resolved.
510+ **/
511+ get currentTargets ( ) : Target [ ] {
512+ return ( this . _contents as unknown as { targets : Target [ ] } ) ?. targets ?? [ ] ;
477513 }
478514
479515 /**
480516 * Return array of targets of a certain type
481517 * @param type Type of target
482518 * @returns Array of targets
483519 */
484- getTargets ( type ?: TargetType ) : Target [ ] {
520+ async getTargets ( type ?: TargetType ) : Promise < Target [ ] > {
485521 if ( type === undefined ) {
486522 return this . targets ;
487523 } else {
488- return this . targets . filter ( target => target . type === type ) ;
524+ return this . targets . then ( targets => targets . filter ( target => target . type === type ) ) ;
489525 }
490526 }
491527
492528 /**
493529 * Get target for file
494530 */
495- getTarget ( file : string ) : Target | undefined {
531+ async getTarget ( file : string ) : Promise < Target | undefined > {
496532 const filePath = path . relative ( this . folder . fsPath , file ) ;
497- return this . targets . find ( target => isPathInsidePath ( filePath , target . path ) ) ;
533+ return this . targets . then ( targets =>
534+ targets . find ( target => isPathInsidePath ( filePath , target . path ) )
535+ ) ;
498536 }
499537
500538 private static trimStdout ( stdout : string ) : string {
0 commit comments