import * as fse from "fs-extra" ; import * as path from "path" ; import { Disposable , QuickInputButtons , QuickPick , QuickPickItem , window } from "vscode" ; import { getMavenLocalRepository , getPathToExtensionRoot } from "../../utils/contextUtils" ; import { Archetype } from "../Archetype" ; import { ArchetypeModule } from "../ArchetypeModule" ; import { IProjectCreationMetadata , IProjectCreationStep , StepResult } from "./types" ; interface IArchetypePickItem extends QuickPickItem { archetype ? : Archetype ; } export class SelectArchetypeStep implements IProjectCreationStep { /**
     * This has to be the first step, no back buttons provided for previous steps.
     */ public readonly previousStep : undefined ; public async run ( metadata ) { const disposables = [ ] ; const specifyAchetypePromise = new Promise < StepResult > ( async ( resolve , _reject ) => { const pickBox = window . createQuickPick < IArchetypePickItem > ( ) ; pickBox . title = "Create Maven Project" ; pickBox . placeholder = "Select an archetype ..." ; pickBox . matchOnDescription = true ; pickBox . ignoreFocusOut = true ; pickBox . items = await this . getArchetypePickItems ( false ) ; disposables . push ( pickBox . onDidTriggerButton ( async ( item ) => { if ( item === QuickInputButtons . Back ) { pickBox . items = await this . getArchetypePickItems ( false ) ; pickBox . buttons = [ ] ; } } ) , pickBox . onDidAccept ( async ( ) => { if ( pickBox . selectedItems [ 0 ] . archetype === undefined ) { pickBox . items = await this . getArchetypePickItems ( true ) ; pickBox . buttons = [ QuickInputButtons . Back ] ; } else { metadata . archetypeArtifactId = pickBox . selectedItems [ 0 ] . archetype . artifactId ; metadata . archetypeGroupId = pickBox . selectedItems [ 0 ] . archetype . groupId ; metadata . archetype = pickBox . selectedItems [ 0 ] . archetype ; resolve ( StepResult . NEXT ) ; } } ) , pickBox . onDidHide ( ( ) => { resolve ( StepResult . STOP ) ; } ) ) ; disposables . push ( pickBox ) ; pickBox . show ( ) ; } ) ; try { return await specifyAchetypePromise ; } finally { disposables . forEach ( d => d . dispose ( ) ) ; } } public async run_simple ( metadata ) { let choice = await window . showQuickPick ( this . getArchetypePickItems ( false ) , { placeHolder : "Select an archetype ..." , ignoreFocusOut : true , matchOnDescription : true } ) ; if ( choice === undefined ) { return StepResult . STOP ; } if ( choice . archetype === undefined ) { choice = await window . showQuickPick ( this . getArchetypePickItems ( true ) , { placeHolder : "Select an archetype ..." , ignoreFocusOut : true , matchOnDescription : true } ) ; } if ( choice ?. archetype !== undefined ) { metadata . archetypeArtifactId = choice . archetype . artifactId ; metadata . archetypeGroupId = choice . archetype . groupId ; metadata . archetype = choice . archetype ; } return StepResult . NEXT ; } private async getArchetypePickItems ( all ? ) { const moreButton = { label : "More..." , description : "" , detail : "Find more archetypes available in remote catalog." , alwaysShow : true } ; const archetypes = await this . loadArchetypePickItems ( all ) ; const pickItems = archetypes . map ( archetype => ( { archetype , label : archetype . artifactId ? `$(package) ${ archetype . artifactId } ` : "More..." , description : archetype . groupId ? `${ archetype . groupId }` : "" , detail : archetype . description } ) ) ; return all ? pickItems : [ moreButton , ... pickItems ] ; } private async loadArchetypePickItems ( all ? ) { const localItems = await this . getLocalArchetypeItems ( ) ; const remoteItems = await this . getCachedRemoteArchetypeItems ( ) ; const localOnlyItems = localItems . filter ( localItem => ! remoteItems . find ( remoteItem => remoteItem . identifier === localItem . identifier ) ) ; if ( all ) { return [ ... localOnlyItems , ... remoteItems ] ; } else { const recommendedItems = await this . getRecommendedItems ( remoteItems ) ; return [ ... localOnlyItems , ... recommendedItems ] ; } } private async getRecommendedItems ( allItems ) { let fixedList ; try { fixedList = await fse . readJSON ( path . join ( getPathToExtensionRoot ( ) , "resources" , "popular_archetypes.json" ) ) ; } catch ( error ) { console . error ( error ) ; } if ( ! fixedList ) { return [ ] ; } else { return fixedList . map ( ( fullname ) => allItems . find ( ( item ) => fullname === `${ item . groupId }:${ item . artifactId }` ) ) . filter ( Boolean ) as Archetype [ ] ; } } private async getLocalArchetypeItems ( ) { const localCatalogPath = path . join ( getMavenLocalRepository ( ) , "archetype-catalog.xml" ) ; if ( await fse . pathExists ( localCatalogPath ) ) { const buf = await fse . readFile ( localCatalogPath ) ; return ArchetypeModule . listArchetypeFromXml ( buf . toString ( ) ) ; } else { return [ ] ; } } private async getCachedRemoteArchetypeItems ( ) { const contentPath = getPathToExtensionRoot ( "resources" , "archetypes.json" ) ; if ( await fse . pathExists ( contentPath ) ) { return ( await fse . readJSON ( contentPath ) ) . map ( ( rawItem ) => new Archetype ( rawItem . artifactId , rawItem . groupId , rawItem . repository , rawItem . description , rawItem . versions ) ) ; } else { return [ ] ; } } }