cosmic-interchain-cli
Version:
A command-line utility for Cosmic Wire's interchain messaging protocol
169 lines • 5.54 kB
JavaScript
import { input } from '@inquirer/prompts';
import select from '@inquirer/select';
import fs from 'fs';
import os from 'os';
import path from 'path';
import { LineCounter, parse, parse as yamlParse, stringify as yamlStringify, } from 'yaml';
import { objMerge } from '@hyperlane-xyz/utils';
import { log } from '../logger.js';
export const MAX_READ_LINE_OUTPUT = 250;
export function resolvePath(filePath) {
if (filePath.startsWith('~')) {
const homedir = os.homedir();
return path.join(homedir, filePath.slice(1));
}
return filePath;
}
export function isFile(filepath) {
if (!filepath)
return false;
try {
return fs.existsSync(filepath) && fs.lstatSync(filepath).isFile();
}
catch (error) {
log(`Error checking for file: ${filepath}`);
return false;
}
}
export function readFileAtPath(filepath) {
if (!isFile(filepath)) {
throw Error(`File doesn't exist at ${filepath}`);
}
return fs.readFileSync(filepath, 'utf8');
}
export function writeFileAtPath(filepath, value) {
const dirname = path.dirname(filepath);
if (!isFile(dirname)) {
fs.mkdirSync(dirname, { recursive: true });
}
fs.writeFileSync(filepath, value);
}
export function readJson(filepath) {
return JSON.parse(readFileAtPath(filepath));
}
export function tryReadJson(filepath) {
try {
return readJson(filepath);
}
catch (error) {
return null;
}
}
export function writeJson(filepath, obj) {
writeFileAtPath(filepath, JSON.stringify(obj, null, 2) + '\n');
}
export function mergeJson(filepath, obj) {
if (isFile(filepath)) {
const previous = readJson(filepath);
writeJson(filepath, objMerge(previous, obj));
}
else {
writeJson(filepath, obj);
}
}
export function readYaml(filepath) {
return yamlParse(readFileAtPath(filepath));
}
export function tryReadYamlAtPath(filepath) {
try {
return readYaml(filepath);
}
catch (error) {
return null;
}
}
export function writeYaml(filepath, obj) {
writeFileAtPath(filepath, yamlStringify(obj, { indent: 2, sortMapEntries: true }) + '\n');
}
export function mergeYaml(filepath, obj) {
if (isFile(filepath)) {
const previous = readYaml(filepath);
writeYaml(filepath, objMerge(previous, obj));
}
else {
writeYaml(filepath, obj);
}
}
export function readYamlOrJson(filepath, format) {
return resolveYamlOrJsonFn(filepath, readJson, readYaml, format);
}
export function writeYamlOrJson(filepath, obj, format) {
return resolveYamlOrJsonFn(filepath, (f) => writeJson(f, obj), (f) => writeYaml(f, obj), format);
}
export function mergeYamlOrJson(filepath, obj, format = 'yaml') {
return resolveYamlOrJsonFn(filepath, (f) => mergeJson(f, obj), (f) => mergeYaml(f, obj), format);
}
function resolveYamlOrJsonFn(filepath, jsonFn, yamlFn, format) {
const fileFormat = resolveFileFormat(filepath, format);
if (!fileFormat) {
throw new Error(`Invalid file format for ${filepath}`);
}
if (fileFormat === 'json') {
return jsonFn(filepath);
}
return yamlFn(filepath);
}
export function resolveFileFormat(filepath, format) {
// early out if filepath is undefined
if (!filepath) {
return format;
}
if (format === 'json' || filepath?.endsWith('.json')) {
return 'json';
}
if (format === 'yaml' ||
filepath?.endsWith('.yaml') ||
filepath?.endsWith('.yml')) {
return 'yaml';
}
return undefined;
}
export async function runFileSelectionStep(folderPath, description, pattern) {
const noFilesErrorMessage = `No "${description}" found in ${folderPath}. Please confirm the path for "${description}". By default, the CLI writes to folders relative to where its run.`;
if (!fs.existsSync(folderPath))
throw new Error(noFilesErrorMessage);
let filenames = fs.readdirSync(folderPath);
if (pattern) {
filenames = filenames.filter((f) => f.includes(pattern));
}
if (filenames.length === 0)
throw new Error(noFilesErrorMessage);
let filename = (await select({
message: `Select ${description} file`,
choices: [
...filenames.map((f) => ({ name: f, value: f })),
{ name: '(Other file)', value: null },
],
pageSize: 20,
}));
if (filename)
return path.join(folderPath, filename);
filename = await input({
message: `Enter ${description} filepath`,
});
if (filename)
return filename;
else
throw new Error(`No filepath entered ${description}`);
}
export function indentYamlOrJson(str, indentLevel) {
const indent = ' '.repeat(indentLevel);
return str
.split('\n')
.map((line) => indent + line)
.join('\n');
}
/**
* Logs the YAML representation of an object if the number of lines is less than the specified maximum.
*
* @param obj - The object to be converted to YAML.
* @param maxLines - The maximum number of lines allowed for the YAML representation.
* @param margin - The number of spaces to use for indentation (default is 2).
*/
export function logYamlIfUnderMaxLines(obj, maxLines = MAX_READ_LINE_OUTPUT, margin = 2) {
const asYamlString = yamlStringify(obj, null, margin);
const lineCounter = new LineCounter();
parse(asYamlString, { lineCounter });
log(lineCounter.lineStarts.length < maxLines ? asYamlString : '');
}
//# sourceMappingURL=files.js.map