import * as fse from 'fs-extra' ; import * as path from 'path' ; import { MessageItem , WorkspaceFolder } from 'vscode' ; import { DialogResponses , IActionContext , IAzureQuickPickItem } from 'vscode-azureextensionui' ; import { hostFileName , projectSubpathSetting } from '../../constants' ; import { localize } from '../../localize' ; import { telemetryUtils } from '../../utils/telemetryUtils' ; import { findFiles } from '../../utils/workspace' ; import * as api from '../../vscode-azurefunctions.api' ; import { getWorkspaceSetting , updateWorkspaceSetting } from '../../vsCodeConfig/settings' ; import { createNewProjectInternal } from './createNewProject' ; export async function isFunctionProject ( folderPath ) { return await fse . pathExists ( path . join ( folderPath , hostFileName ) ) ; } /**
 * Describes what to do if multiple projects are found
 */ export type MultiProjectPromptBehavior = 'silent' | 'prompt' | 'modalPrompt' ; param workspaceFolder export async function tryGetFunctionProjectRoot ( context , workspaceFolder , promptBehavior = 'silent' ) { return await telemetryUtils . runWithDurationTelemetry ( context , 'tryGetProject' , async ( ) => { const folderPath = typeof workspaceFolder === 'string' ? workspaceFolder : workspaceFolder . uri . fsPath ; if ( ! getWorkspaceSetting < boolean > ( 'suppressProject' , workspaceFolder ) ) { const subpath = getWorkspaceSetting ( projectSubpathSetting , workspaceFolder ) ; if ( subpath ) { return path . join ( folderPath , subpath ) ; } else if ( await fse . pathExists ( folderPath ) ) { if ( await isFunctionProject ( folderPath ) ) { return folderPath ; } else { const hostJsonUris = await findFiles ( workspaceFolder , `*/${ hostFileName }` ) ; if ( hostJsonUris . length !== 1 ) { hostJsonUris . push ( ... await findFiles ( workspaceFolder , `*/*/**/${ hostFileName }` ) ) ; } const projectPaths = hostJsonUris . map ( uri => path . dirname ( uri . fsPath ) ) ; if ( projectPaths . length === 1 ) { return projectPaths [ 0 ] ; } else if ( projectPaths . length > 1 && promptBehavior !== 'silent' ) { const subpaths = projectPaths . map ( p => path . relative ( folderPath , p ) ) ; const pickedSubpath = await promptForProjectSubpath ( context , folderPath , subpaths , promptBehavior ) ; return path . join ( folderPath , pickedSubpath ) ; } } } } return undefined ; } ) ; } async function promptForProjectSubpath ( context , workspacePath , matchingSubpaths , promptBehavior ) { const message = localize ( 'detectedMultipleProject' , 'Detected multiple function projects in the same workspace folder. You must either set the default or use a multi-root workspace.' ) ; const learnMoreLink = 'https://aka.ms/AA4nmfy' ; const setDefault = { title : localize ( 'setDefault' , 'Set default' ) } ; await context . ui . showWarningMessage ( message , { learnMoreLink , modal : promptBehavior === 'modalPrompt' , stepName : 'multipleProjects' } , setDefault ) ; const picks = matchingSubpaths . map ( p => { return { label : p , data : p } ; } ) ; const placeHolder = localize ( 'selectProject' , 'Select the default project subpath' ) ; const subpath = ( await context . ui . showQuickPick ( picks , { placeHolder , stepName : 'multipleProjects|select' } ) ) . data ; await updateWorkspaceSetting ( projectSubpathSetting , subpath , workspacePath ) ; return subpath ; } /**
 * Checks if the path is already a function project. If not, it will prompt to create a new project and return undefined
 */ export async function verifyAndPromptToCreateProject ( context , workspaceFolder , options ? ) { options = options || { } ; const projectPath = await tryGetFunctionProjectRoot ( context , workspaceFolder , 'modalPrompt' ) ; if ( ! projectPath ) { if ( ! options . suppressCreateProjectPrompt ) { const message = localize ( 'notFunctionApp' , 'The selected folder is not a function project. Create new project?' ) ; await context . ui . showWarningMessage ( message , { modal : true , stepName : 'notAProject' } , DialogResponses . yes ) ; } options . folderPath ||= typeof workspaceFolder === 'string' ? workspaceFolder : workspaceFolder . uri . fsPath ; await createNewProjectInternal ( context , options ) ; return undefined ; } else { return projectPath ; } }