@@ -18,114 +18,75 @@ import { OmniSharpServer } from './omnisharp/server';
1818import { tolerantParse } from './json' ;
1919
2020export class AssetGenerator {
21- public workspaceFolder : vscode . WorkspaceFolder ;
2221 public vscodeFolder : string ;
2322 public tasksJsonPath : string ;
2423 public launchJsonPath : string ;
2524
26- private executeableProjects : protocol . MSBuildProject [ ] ;
25+ private executableProjects : protocol . MSBuildProject [ ] = [ ] ;
2726 private startupProject : protocol . MSBuildProject | undefined ;
28- private fallbackBuildProject : protocol . MSBuildProject ;
29-
30- public constructor ( workspaceInfo : protocol . WorkspaceInformationResponse , workspaceFolder : vscode . WorkspaceFolder = undefined ) {
31- if ( workspaceFolder ) {
32- this . workspaceFolder = workspaceFolder ;
33- }
34- else {
35- let resourcePath : string = undefined ;
36-
37- if ( ! resourcePath && workspaceInfo . Cake ) {
38- resourcePath = workspaceInfo . Cake . Path ;
39- }
40-
41- if ( ! resourcePath && workspaceInfo . ScriptCs ) {
42- resourcePath = workspaceInfo . ScriptCs . Path ;
43- }
44-
45- if ( ! resourcePath && workspaceInfo . DotNet && workspaceInfo . DotNet . Projects . length > 0 ) {
46- resourcePath = workspaceInfo . DotNet . Projects [ 0 ] . Path ;
47- }
48-
49- if ( ! resourcePath && workspaceInfo . MsBuild ) {
50- resourcePath = workspaceInfo . MsBuild . SolutionPath ;
51- }
52-
53- this . workspaceFolder = vscode . workspace . getWorkspaceFolder ( vscode . Uri . file ( resourcePath ) ) ;
54- }
27+ private fallbackBuildProject : protocol . MSBuildProject | undefined ;
5528
29+ public constructor ( workspaceInfo : protocol . WorkspaceInformationResponse , private workspaceFolder : vscode . WorkspaceFolder ) {
5630 this . vscodeFolder = path . join ( this . workspaceFolder . uri . fsPath , '.vscode' ) ;
5731 this . tasksJsonPath = path . join ( this . vscodeFolder , 'tasks.json' ) ;
5832 this . launchJsonPath = path . join ( this . vscodeFolder , 'launch.json' ) ;
5933
60- this . startupProject = undefined ;
61- this . fallbackBuildProject = undefined ;
62-
63- if ( workspaceInfo . MsBuild && workspaceInfo . MsBuild . Projects . length > 0 ) {
64- this . executeableProjects = protocol . findExecutableMSBuildProjects ( workspaceInfo . MsBuild . Projects ) ;
65- if ( this . executeableProjects . length === 0 ) {
34+ if ( workspaceInfo . MsBuild !== undefined && workspaceInfo . MsBuild . Projects . length > 0 ) {
35+ this . executableProjects = protocol . findExecutableMSBuildProjects ( workspaceInfo . MsBuild . Projects ) ;
36+ if ( this . executableProjects . length === 0 ) {
6637 this . fallbackBuildProject = workspaceInfo . MsBuild . Projects [ 0 ] ;
6738 }
68- } else {
69- this . executeableProjects = [ ] ;
7039 }
7140 }
7241
7342 public hasExecutableProjects ( ) : boolean {
74- return this . executeableProjects . length > 0 ;
43+ return this . executableProjects . length > 0 ;
7544 }
7645
7746 public isStartupProjectSelected ( ) : boolean {
78- if ( this . startupProject ) {
79- return true ;
80- } else {
81- return false ;
82- }
47+ return this . startupProject !== undefined ;
8348 }
8449
8550 public async selectStartupProject ( selectedIndex ?: number ) : Promise < boolean > {
8651 if ( ! this . hasExecutableProjects ( ) ) {
8752 throw new Error ( "No executable projects" ) ;
8853 }
8954
90- if ( this . executeableProjects . length === 1 ) {
91- this . startupProject = this . executeableProjects [ 0 ] ;
55+ if ( selectedIndex !== undefined ) {
56+ this . startupProject = this . executableProjects [ selectedIndex ] ;
9257 return true ;
93- } else {
94- const mapItemNameToProject : { [ key : string ] : protocol . MSBuildProject } = { } ;
95- const itemNames : string [ ] = [ ] ;
58+ }
9659
97- this . executeableProjects . forEach ( project => {
98- const itemName = `${ path . basename ( project . Path , ".csproj" ) } (${ project . Path } )` ;
99- itemNames . push ( itemName ) ;
100- mapItemNameToProject [ itemName ] = project ;
60+ if ( this . executableProjects . length === 1 ) {
61+ this . startupProject = this . executableProjects [ 0 ] ;
62+ return true ;
63+ } else {
64+ const items = this . executableProjects . map ( project => ( {
65+ label : `${ path . basename ( project . Path , ".csproj" ) } (${ project . Path } )` ,
66+ project,
67+ } ) ) ;
68+
69+ const selectedItem = await vscode . window . showQuickPick ( items , {
70+ matchOnDescription : true ,
71+ placeHolder : "Select the project to launch"
10172 } ) ;
10273
103- let selectedItem : string ;
104- if ( selectedIndex != null ) {
105- selectedItem = itemNames [ selectedIndex ] ;
106- }
107- else {
108- selectedItem = await vscode . window . showQuickPick ( itemNames , {
109- matchOnDescription : true ,
110- placeHolder : "Select the project to launch"
111- } ) ;
112- }
113- if ( ! selectedItem || ! mapItemNameToProject [ selectedItem ] ) {
74+ if ( selectedItem === undefined ) {
11475 return false ;
11576 }
11677
117- this . startupProject = mapItemNameToProject [ selectedItem ] ;
78+ this . startupProject = selectedItem . project ;
11879 return true ;
11980 }
12081 }
12182
12283 // This method is used by the unit tests instead of selectStartupProject
12384 public setStartupProject ( index : number ) : void {
124- if ( index >= this . executeableProjects . length ) {
85+ if ( index >= this . executableProjects . length ) {
12586 throw new Error ( "Invalid project index" ) ;
12687 }
12788
128- this . startupProject = this . executeableProjects [ index ] ;
89+ this . startupProject = this . executableProjects [ index ] ;
12990 }
13091
13192 public hasWebServerDependency ( ) : boolean {
@@ -465,9 +426,9 @@ async function getOperations(generator: AssetGenerator): Promise<AssetOperations
465426function getBuildTasks ( tasksConfiguration : tasks . TaskConfiguration ) : tasks . TaskDescription [ ] {
466427 let result : tasks . TaskDescription [ ] = [ ] ;
467428
468- function findBuildTask ( version : string , tasksDescriptions : tasks . TaskDescription [ ] ) {
429+ function findBuildTask ( tasksDescriptions : tasks . TaskDescription [ ] | undefined ) {
469430 let buildTask = undefined ;
470- if ( tasksDescriptions ) {
431+ if ( tasksDescriptions !== undefined ) {
471432 buildTask = tasksDescriptions . find ( td => td . group === 'build' ) ;
472433 }
473434
@@ -476,18 +437,18 @@ function getBuildTasks(tasksConfiguration: tasks.TaskConfiguration): tasks.TaskD
476437 }
477438 }
478439
479- findBuildTask ( tasksConfiguration . version , tasksConfiguration . tasks ) ;
440+ findBuildTask ( tasksConfiguration . tasks ) ;
480441
481442 if ( tasksConfiguration . windows ) {
482- findBuildTask ( tasksConfiguration . version , tasksConfiguration . windows . tasks ) ;
443+ findBuildTask ( tasksConfiguration . windows . tasks ) ;
483444 }
484445
485446 if ( tasksConfiguration . osx ) {
486- findBuildTask ( tasksConfiguration . version , tasksConfiguration . osx . tasks ) ;
447+ findBuildTask ( tasksConfiguration . osx . tasks ) ;
487448 }
488449
489450 if ( tasksConfiguration . linux ) {
490- findBuildTask ( tasksConfiguration . version , tasksConfiguration . linux . tasks ) ;
451+ findBuildTask ( tasksConfiguration . linux . tasks ) ;
491452 }
492453
493454 return result ;
@@ -618,13 +579,13 @@ export async function addTasksJsonIfNecessary(generator: AssetGenerator, operati
618579 if ( ! fs . pathExistsSync ( generator . tasksJsonPath ) ) {
619580 // when tasks.json does not exist create it and write all the content directly
620581 const tasksJsonText = JSON . stringify ( tasksJson ) ;
621- const tasksJsonTextFormatted = jsonc . applyEdits ( tasksJsonText , jsonc . format ( tasksJsonText , null , formattingOptions ) ) ;
582+ const tasksJsonTextFormatted = jsonc . applyEdits ( tasksJsonText , jsonc . format ( tasksJsonText , undefined , formattingOptions ) ) ;
622583 text = tasksJsonTextFormatted ;
623584 }
624585 else {
625586 // when tasks.json exists just update the tasks node
626- const ourConfigs = tasksJson . tasks ;
627- const content = fs . readFileSync ( generator . tasksJsonPath ) . toString ( ) ;
587+ const ourConfigs = tasksJson . tasks ?? [ ] ;
588+ const content = fs . readFileSync ( generator . tasksJsonPath , { encoding : 'utf8' } ) ;
628589 const updatedJson = updateJsonWithComments ( content , ourConfigs , 'tasks' , 'label' , formattingOptions ) ;
629590 text = updatedJson ;
630591 }
@@ -660,12 +621,12 @@ async function addLaunchJsonIfNecessary(generator: AssetGenerator, operations: A
660621 "configurations": ${ configurationsMassaged }
661622 }` ;
662623
663- text = jsonc . applyEdits ( launchJsonText , jsonc . format ( launchJsonText , null , formattingOptions ) ) ;
624+ text = jsonc . applyEdits ( launchJsonText , jsonc . format ( launchJsonText , undefined , formattingOptions ) ) ;
664625 }
665626 else {
666627 // when launch.json exists replace or append our configurations
667- const ourConfigs = jsonc . parse ( launchJsonConfigurations ) ;
668- const content = fs . readFileSync ( generator . launchJsonPath ) . toString ( ) ;
628+ const ourConfigs = jsonc . parse ( launchJsonConfigurations ) ?? [ ] ;
629+ const content = fs . readFileSync ( generator . launchJsonPath , { encoding : 'utf8' } ) ;
669630 const updatedJson = updateJsonWithComments ( content , ourConfigs , 'configurations' , 'name' , formattingOptions ) ;
670631 text = updatedJson ;
671632 }
@@ -711,15 +672,29 @@ export async function addAssetsIfNecessary(server: OmniSharpServer): Promise<Add
711672 }
712673
713674 serverUtils . requestWorkspaceInformation ( server ) . then ( async info => {
714- const generator = new AssetGenerator ( info ) ;
675+ const resourcePath = info . Cake ?. Path ??
676+ info . ScriptCs ?. Path ??
677+ info . DotNet ?. Projects ?. [ 0 ] . Path ??
678+ info . MsBuild ?. SolutionPath ;
679+ if ( resourcePath === undefined ) {
680+ // This shouldn't happen, but it's a cheap check.
681+ return resolve ( AddAssetResult . NotApplicable ) ;
682+ }
683+
684+ const workspaceFolder = vscode . workspace . getWorkspaceFolder ( vscode . Uri . file ( resourcePath ) ) ;
685+ if ( workspaceFolder === undefined ) {
686+ return resolve ( AddAssetResult . NotApplicable ) ;
687+ }
688+
689+ const generator = new AssetGenerator ( info , workspaceFolder ) ;
715690 // If there aren't executable projects, we will not prompt
716691 if ( generator . hasExecutableProjects ( ) ) {
717692 return getOperations ( generator ) . then ( operations => {
718693 if ( ! hasAddOperations ( operations ) ) {
719694 return resolve ( AddAssetResult . NotApplicable ) ;
720695 }
721696
722- promptToAddAssets ( generator . workspaceFolder ) . then ( result => {
697+ promptToAddAssets ( workspaceFolder ) . then ( result => {
723698 if ( result === PromptResult . Disable ) {
724699 return resolve ( AddAssetResult . Disable ) ;
725700 }
@@ -775,7 +750,7 @@ async function getExistingAssets(generator: AssetGenerator) {
775750async function shouldGenerateAssets ( generator : AssetGenerator ) : Promise < Boolean > {
776751 return new Promise < Boolean > ( ( resolve , reject ) => {
777752 getExistingAssets ( generator ) . then ( res => {
778- if ( res && res . length ) {
753+ if ( res . length > 0 ) {
779754 const yesItem = { title : 'Yes' } ;
780755 const cancelItem = { title : 'Cancel' , isCloseAffordance : true } ;
781756 vscode . window . showWarningMessage ( 'Replace existing build and debug assets?' , cancelItem , yesItem )
@@ -802,7 +777,13 @@ export async function generateAssets(server: OmniSharpServer, selectedIndex?: nu
802777 try {
803778 let workspaceInformation = await serverUtils . requestWorkspaceInformation ( server ) ;
804779 if ( workspaceInformation . MsBuild && workspaceInformation . MsBuild . Projects . length > 0 ) {
805- const generator = new AssetGenerator ( workspaceInformation ) ;
780+ const resourcePath = workspaceInformation . MsBuild . SolutionPath ;
781+ const workspaceFolder = vscode . workspace . getWorkspaceFolder ( vscode . Uri . file ( resourcePath ) ) ;
782+ if ( workspaceFolder === undefined ) {
783+ return ;
784+ }
785+
786+ const generator = new AssetGenerator ( workspaceInformation , workspaceFolder ) ;
806787 let doGenerateAssets = await shouldGenerateAssets ( generator ) ;
807788 if ( ! doGenerateAssets ) {
808789 return ; // user cancelled
0 commit comments