import * as fse from "fs-extra" ; import * as path from "path" ; import * as vscode from "vscode" ; import { MavenProject } from "../explorer/model/MavenProject" ; import { constructDependenciesNode , constructDependencyNode , getIndentation } from "../utils/editUtils" ; import { UserError } from "../utils/errorUtils" ; import { ElementNode , getNodesByTag , XmlTagName } from "../utils/lexerUtils" ; import { getArtifacts , IArtifactMetadata } from "../utils/requestUtils" ; import { selectProjectIfNecessary } from "../utils/uiUtils" ; export async function addDependencyHandler ( options ? ) { let pomPath ; if ( options && options . pomPath ) { pomPath = options . pomPath ; } else if ( options && options . projectBasePath ) { pomPath = path . join ( options . projectBasePath , "pom.xml" ) ; } else if ( options ?. project ?. pomPath ) { pomPath = options . project . pomPath ; } else { const selectedProject = await selectProjectIfNecessary ( ) ; if ( ! selectedProject ) { return ; } pomPath = selectedProject . pomPath ; } if ( ! await fse . pathExists ( pomPath ) ) { throw new UserError ( "Specified POM file does not exist on file system." ) ; } if ( options && options . groupId && options . artifactId && options . version ) { await addDependency ( pomPath , options . groupId , options . artifactId , options . version , options . packaging , options . classifier ) ; } else { const keywordString = await vscode . window . showInputBox ( { ignoreFocusOut : true , prompt : "Input keywords to search artifacts from Maven Central Repository." , placeHolder : "e.g. spring azure storage" , validateInput : ( text ) => { if ( text . trim ( ) . length < 3 ) { return "Keywords are too short." ; } return undefined ; } } ) ; if ( ! keywordString ) { return ; } const selectedDoc = await vscode . window . showQuickPick < vscode . QuickPickItem & { value : IArtifactMetadata ; } > ( getArtifacts ( keywordString . trim ( ) . split ( /[-,. :]/ ) ) . then ( artifacts => artifacts . map ( artifact => ( { value : artifact , label : `$(package) ${ artifact . a }` , description : artifact . g } ) ) ) , { placeHolder : "Select a dependency ..." } ) . then ( selected => selected ? selected . value : undefined ) ; if ( ! selectedDoc ) { return ; } await addDependency ( pomPath , selectedDoc . g , selectedDoc . a , selectedDoc . latestVersion , selectedDoc . p , undefined ) ; } } async function addDependency ( pomPath , gid , aid , version , dependencyType , classifier ? ) { const pomDocument = await vscode . window . showTextDocument ( vscode . Uri . file ( pomPath ) , { preserveFocus : true } ) ; const projectNodes = getNodesByTag ( pomDocument . document . getText ( ) , XmlTagName . Project ) ; if ( projectNodes === undefined || projectNodes . length !== 1 ) { throw new UserError ( "Only support POM file with single <project> node." ) ; } const projectNode = projectNodes [ 0 ] ; const dependenciesNode = projectNode . children ?. find ( node => node . tag === XmlTagName . Dependencies ) ; if ( dependenciesNode !== undefined ) { await insertDependency ( pomPath , dependenciesNode , gid , aid , version , dependencyType , classifier ) ; } else { await insertDependency ( pomPath , projectNode , gid , aid , version , dependencyType , classifier ) ; } } async function insertDependency ( pomPath , targetNode , gid , aid , version , dependencyType , classifier ? ) { if ( targetNode . contentStart === undefined || targetNode . contentEnd === undefined ) { throw new UserError ( "Invalid target XML node to insert dependency." ) ; } const currentDocument = await vscode . workspace . openTextDocument ( pomPath ) ; const textEditor = await vscode . window . showTextDocument ( currentDocument ) ; const baseIndent = getIndentation ( currentDocument , targetNode . contentEnd ) ; const options = textEditor . options ; const indent = options . insertSpaces && typeof options . tabSize === "number" ? " " . repeat ( options . tabSize ) : "\t" ; const eol = currentDocument . eol === vscode . EndOfLine . LF ? "\n" : "\r\n" ; let insertPosition ; let targetText ; if ( targetNode . tag === XmlTagName . Dependencies ) { insertPosition = currentDocument . positionAt ( targetNode . contentStart ) ; targetText = constructDependencyNode ( { gid , aid , version , dtype : dependencyType , classifier , baseIndent , indent , eol } ) ; } else if ( targetNode . tag === XmlTagName . Project ) { insertPosition = currentDocument . positionAt ( targetNode . contentEnd ) ; targetText = constructDependenciesNode ( { gid , aid , version , dtype : dependencyType , classifier , baseIndent , indent , eol } ) ; } else { return ; } const edit = new vscode . WorkspaceEdit ( ) ; edit . insert ( currentDocument . uri , insertPosition , targetText ) ; await vscode . workspace . applyEdit ( edit ) ; const endingPosition = currentDocument . positionAt ( currentDocument . offsetAt ( insertPosition ) + targetText . length ) ; textEditor . revealRange ( new vscode . Range ( insertPosition , endingPosition ) ) ; }