'use strict' ; import * as vscode from 'vscode' ; import * as nls from 'vscode-nls' ; import { Reporter } from '../util/Reporter' ; import { VSCodeBlockchainOutputAdapter } from '../logging/VSCodeBlockchainOutputAdapter' ; import * as path from 'path' ; import { UserInputUtil , LanguageQuickPickItem , LanguageType , IBlockchainQuickPickItem } from './UserInputUtil' ; import { ExtensionUtil } from '../util/ExtensionUtil' ; import { LogType } from 'ibm-blockchain-platform-common' ; import * as GeneratorFabricPackageJSON from 'generator-fabric/package.json' ; import { YeomanUtil } from '../util/YeomanUtil' ; const localize = nls . loadMessageBundle ( ) ; export async function createSmartContractProject ( ) { const outputAdapter = VSCodeBlockchainOutputAdapter . instance ( ) ; let chaincodeLanguageOptions = getChaincodeLanguageOptions ( ) ; const smartContractLanguageOptions = getSmartContractLanguageOptions ( ) ; let contractType ; let privateOrDefault ; const pdContract = ' Private Data ' ; const defaultContract = ' ' ; const typeDefault = 'default' ; const defaultAsset = 'MyAsset' ; const privateAsset = 'MyPrivateAsset' ; contractType = await UserInputUtil . showQuickPickItem ( 'Choose a contract type to generate:' , [ { label : UserInputUtil . GENERATE_DEFAULT_CONTRACT , description : UserInputUtil . GENERATE_DEFAULT_CONTRACT_DESCRIPTION , data : 'default' } , { label : UserInputUtil . GENERATE_PD_CONTRACT , description : UserInputUtil . GENERATE_PD_CONTRACT_DESCRIPTION , data : 'private' } ] as IBlockchainQuickPickItem < string > [ ] ) as IBlockchainQuickPickItem < string > ; if ( ! contractType ) { return ; } if ( contractType . data === typeDefault ) { privateOrDefault = defaultContract ; } else { privateOrDefault = pdContract ; } const smartContractLanguagePrompt = localize ( 'smartContractLanguage.prompt' , 'Choose smart contract language (Esc to cancel)' ) ; if ( contractType . data !== typeDefault ) { chaincodeLanguageOptions = [ ] ; } const smartContractLanguageItem = await UserInputUtil . showLanguagesQuickPick ( smartContractLanguagePrompt , chaincodeLanguageOptions , smartContractLanguageOptions ) ; if ( ! smartContractLanguageItem ) { return ; } const generator = `fabric:${ smartContractLanguageItem . type . toLowerCase ( ) }` ; const smartContractLanguage = smartContractLanguageItem . label . toLowerCase ( ) ; let assetType ; if ( smartContractLanguageItem . type === LanguageType . CONTRACT ) { assetType = await UserInputUtil . showInputBox ( 'Name the type of asset managed by this smart contract' , contractType . data === typeDefault ? defaultAsset : privateAsset ) ; const regexForAssetType = /^[A-Z]+$/i ; const validAssetType = regexForAssetType . test ( assetType ) ; if ( ! assetType ) { return ; } if ( ! validAssetType ) { outputAdapter . log ( LogType . ERROR , `Invalid asset name, it should only contain lowercase and uppercase letters.` ) ; return ; } } const quickPickItem = { label : UserInputUtil . BROWSE_LABEL , description : UserInputUtil . VALID_FOLDER_NAME } ; const openDialogOptions = { canSelectFiles : false , canSelectFolders : true , canSelectMany : false , openLabel : 'Save' , filters : undefined } ; const folderUri = await UserInputUtil . browse ( 'Choose the location to save the smart contract.' , quickPickItem , openDialogOptions , true ) as vscode . Uri ; if ( ! folderUri ) { return ; } const folderPath = folderUri . fsPath ; const folderName = path . basename ( folderPath ) ; const regex = /^[a-zA-Z0-9-_]+$/ ; const validPackageName = regex . test ( folderName ) ; if ( ! validPackageName ) { outputAdapter . log ( LogType . ERROR , `Please choose a folder which only includes alphanumeric, "_" and "-" characters.` ) ; return ; } const openMethod = await UserInputUtil . showFolderOptions ( 'Choose how to open your new project' ) ; if ( ! openMethod ) { return ; } try { const skipInstall = ExtensionUtil . skipNpmInstall ( ) ; const runOptions = { 'destination' : folderPath , 'contractType' : contractType . data , 'language' : smartContractLanguage , 'name' : folderName , 'version' : '0.0.1' , 'description' : `My${ privateOrDefault }Smart Contract` , 'author' : 'John Doe' , 'license' : 'Apache-2.0' , 'skip-install' : skipInstall , 'asset' : assetType } ; await vscode . window . withProgress ( { location : vscode . ProgressLocation . Notification , title : 'IBM Blockchain Platform Extension' , cancellable : false } , async ( progress ) : Promise < void > => { progress . report ( { message : `Generating${ privateOrDefault }Smart Contract Project` } ) ; await YeomanUtil . run ( generator , runOptions ) ; } ) ; outputAdapter . log ( LogType . SUCCESS , `Successfully generated${ privateOrDefault }Smart Contract Project` ) ; Reporter . instance ( ) . sendTelemetryEvent ( 'createSmartContractProject' , { contractLanguage : smartContractLanguage , contractType : contractType . data } ) ; await UserInputUtil . openNewProject ( openMethod , folderUri ) ; try { await vscode . commands . executeCommand ( 'workbench.files.action.focusFilesExplorer' ) ; } catch ( error ) { } } catch ( error ) { outputAdapter . log ( LogType . ERROR , `Issue creating${ privateOrDefault }Smart Contract Project: ${ error . message }` , `Issue creating${ privateOrDefault }Smart Contract Project: ${ error . toString ( ) }` ) ; return ; } } function getChaincodeLanguageOptions ( ) { return GeneratorFabricPackageJSON . chaincodeLanguages ; } function getSmartContractLanguageOptions ( ) { return GeneratorFabricPackageJSON . contractLanguages ; }