diff --git a/src/configManager.ts b/src/configManager.ts index df78516..ead90e6 100644 --- a/src/configManager.ts +++ b/src/configManager.ts @@ -1,81 +1,128 @@ import axios from 'axios'; import * as path from 'path'; import * as mkdirpCallback from 'mkdirp'; -import * as rimrafCallback from 'rimraf'; import { readFile as readFileCallback, writeFile as writeFileCallback, exists as existsCallback, } from 'fs'; import { promisify } from 'util'; +import * as spinner from './cli/logIndicator'; const exists = promisify(existsCallback); const mkdirp = promisify(mkdirpCallback); -const rimraf = promisify(rimrafCallback); const writeFile = promisify(writeFileCallback); const readFile = promisify(readFileCallback); -const configDirectory = '.lamington'; -const configFilePath = path.join(configDirectory, 'config.json'); -const encoding = 'utf8'; +/** Root config directory path */ +const CONFIG_DIRECTORY = '.lamington'; +/** Config file fullpath */ +const CONFIG_FILE_PATH = path.join(CONFIG_DIRECTORY, 'config.json'); +/** Default encoding */ +const ENCODING = 'utf8'; +/** EOSIO and EOSIO.CDT configuration file paths */ export interface LamingtonConfig { cdt: string; eos: string; + keepAlive: boolean; } +/** + * Fetches and stores the latest EOS configuration images + * @author Kevin Brown + */ export class ConfigManager { + + /** + * EOSIO and EOSIO.CDT configuration settings + * @author Kevin Brown + */ private static config: LamingtonConfig; - private static async getAssetURL(organisation: string, repository: string, filter: string) { - // Get the latest releases from GitHub and search for the asset. - const result = await axios.get( - `https://api.github.com/repos/${organisation}/${repository}/releases/latest` - ); - + /** + * Downloads the organization's latest repository release image and + * returns the assets matching the specified filter + * @author Kevin Brown + * @param organization Asset's case-sensitive repository organization + * @param repository Asset's case-sensitive repository name + * @param filter Resource filter + */ + private static async getAssetURL(organization: string, repository: string, filter: string) { + // Get the projects latest GitHub repository release + const result = await axios.get(`https://api.github.com/repos/${organization}/${repository}/releases/latest`); + // Handle failed GitHub request if (!result.data || !result.data.assets || !Array.isArray(result.data.assets)) { console.error(result); throw new Error('Unexpected response from GitHub API.'); } - + // Capture the GitHub url from response const asset = result.data.assets.find((asset: any) => asset.browser_download_url.includes(filter) ); - - if (!asset) { - throw new Error( - `Could not locate asset with ${filter} in the download URL in the ${organisation}/${repository} repository` - ); - } - + // Handle no assets found + if (!asset) throw new Error ( + `Could not locate asset with ${filter} in the download URL in the ${organization}/${repository} repository` + ); + // Return captured download url return asset.browser_download_url as string; } + /** + * Fetches the latest EOS repository release and freezes version changes + * in [[CONFIG_FILE_PATH]] to maintain a consistent development environment + * @author Kevin Brown + */ public static async initWithDefaults() { - // Get the latest releases from GitHub, then freeze them into a config file - // so as people work the versions don't change. - if (!(await exists(configFilePath))) { + // Begin log output + spinner.create('Loading configuration...'); + // Check if configuration exists + if (!(await exists(CONFIG_FILE_PATH))) { + // Fetch the latest repository configuration const defaultConfig: LamingtonConfig = { cdt: await ConfigManager.getAssetURL('EOSIO', 'eosio.cdt', 'amd64.deb'), eos: await ConfigManager.getAssetURL('EOSIO', 'eos', 'ubuntu-18.04'), + keepAlive:false }; - - await mkdirp(configDirectory); - await writeFile(configFilePath, JSON.stringify(defaultConfig, null, 4), encoding); + // Create and/or update configuration file + await mkdirp(CONFIG_DIRECTORY); + await writeFile(CONFIG_FILE_PATH, JSON.stringify(defaultConfig, null, 4), ENCODING); } - + // Load existing configuration await ConfigManager.loadConfigFromDisk(); + spinner.end(); } + /** + * Loads the existing configuration file into [[ConfigManager.config]] + * @author Kevin Brown + */ private static async loadConfigFromDisk() { - ConfigManager.config = JSON.parse(await readFile(configFilePath, encoding)); + // Read existing configuration and store + ConfigManager.config = JSON.parse(await readFile(CONFIG_FILE_PATH, ENCODING)); } + /** + * Returns the current EOSIO configuration + * @author Kevin Brown + */ static get eos() { return ConfigManager.config.eos; } + /** + * Returns the current EOSIO.CDT configuration + * @author Kevin Brown + */ static get cdt() { return ConfigManager.config.cdt; } + + /** + * Returns the EOSIO keep alive setting or false + * @author Mitch Pierias + */ + static get keepAlive() { + return ConfigManager.config.keepAlive || false; + } } diff --git a/src/contracts/typeGenerator.ts b/src/contracts/typeGenerator.ts index f3ac9ff..e3d97b1 100644 --- a/src/contracts/typeGenerator.ts +++ b/src/contracts/typeGenerator.ts @@ -3,6 +3,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { promisify } from 'util'; import mapTypes from './typeMap'; +import * as spinner from './../cli/logIndicator'; const glob = promisify(globWithCallbacks); @@ -16,8 +17,7 @@ type IndentedGeneratorLevel = { [key: string]: Array | IndentedGenerator type GeneratorLevel = Array; /** - * Map Paramater Type - * @desc Parses a C++ type definition into a Typescript definition + * Parses a C++ type definition into a Typescript definition * @author Kevin Brown * @author Mitch Pierias * @param eosType @@ -33,21 +33,28 @@ export const mapParameterType = (eosType: string) => { } }; +/** + * Loads all `.abi` files and generates types + * @author Kevin Brown + */ export const generateAllTypes = async () => { - // Make sure there are files to even generate from. + // Load all `.abi` files const files = await glob('**/*.abi'); - - if (files.length === 0) { - throw new Error('No ABI files to generate from. Exiting.'); - } - - for (const file of files) { - await generateTypes(file); - } + // Handle no files found + if (files.length === 0) throw new Error('No ABI files to generate from. Exiting.'); + // Generate types for each file + for (const file of files) await generateTypes(file); }; +/** + * Generates a Typescript definition file from a contract ABI file + * @author Kevin Brown + * @author Mitch Pierias + * @param contractIdentifier Path to file without extension + */ export const generateTypes = async (contractIdentifier: string) => { - console.log(`Generating types for ${contractIdentifier}`); + // Notify generating has begun + spinner.create(`Generating types definitions`); const contractName = path.basename(contractIdentifier); const abiPath = path.join('.lamington', 'compiled_contracts', `${contractIdentifier}.abi`); @@ -58,7 +65,7 @@ export const generateTypes = async (contractIdentifier: string) => { {}, ...abi.structs.map((struct: any) => ({ [struct['name']]: struct })) ); - + // Prepend warning text const result: GeneratorLevel = [ '// =====================================================', '// WARNING: GENERATED FILE', @@ -67,7 +74,6 @@ export const generateTypes = async (contractIdentifier: string) => { '// =====================================================', '', ]; - // Imports const imports = ['Account', 'Contract']; if (contractTables.length > 0) imports.push('TableRowsResult'); @@ -86,7 +92,6 @@ export const generateTypes = async (contractIdentifier: string) => { result.push(tableInterface); result.push(''); } - // Generate contract type from ABI const generatedContractActions = contractActions.map((action: any) => { // With a function for each action @@ -119,6 +124,7 @@ export const generateTypes = async (contractIdentifier: string) => { result.push(''); await saveInterface(contractIdentifier, result); + spinner.end(''); }; const saveInterface = async (