@kadena/kadena-cli
Version:
Kadena CLI tool to interact with the Kadena blockchain (manage keys, transactions, etc.)
201 lines • 7.31 kB
JavaScript
import { load } from 'js-yaml';
import path from 'path';
import sanitize from 'sanitize-filename';
import { MAX_CHAIN_IDS, MAX_CHARACTERS_LENGTH } from '../constants/config.js';
import { services } from '../services/index.js';
/**
* Assigns a value to an object's property if the value is neither undefined nor an empty string.
* This function provides a type-safe way to conditionally update properties on an object.
*
* @template T - The type of the object to which the value might be assigned.
* @template K - The type of the property key on the object.
* @param {T} obj - The target object to which the value might be assigned.
* @param {K} key - The property key on the object where the value might be assigned.
* @param {T[K] | undefined} value - The value to be potentially assigned. If undefined or empty string, no assignment occurs.
*/
export function safeAssign(obj, key, value) {
if (value !== undefined && value !== '') {
obj[key] = value;
}
}
/**
* Merges properties from the source object into the target object,
* overwriting properties on the target only if they are defined in the source.
*
* @template T - The type of the target object and the source object.
* @param {T} target - The target object that will receive properties from the source.
* @param {Partial<T>} source - The source object from which properties will be taken.
* @returns {T} - The merged object.
*/
export function mergeConfigs(target, source) {
for (const key in source) {
if (key in target) {
safeAssign(target, key, source[key]);
}
}
return target;
}
/**
* Sanitizes a string to create a safe filename by replacing illegal, control,
* reserved and trailing characters with hyphens. It ensures that the file does
* not end with a hyphen.
*
* @param {string} str - The input string that needs to be sanitized.
* @returns {string} - The sanitized string, ensuring it does not end with a hyphen.
*
* @example
* const originalString = "This is a <sample> string:file\\name?";
* const sanitizedString = sanitizeFilename(originalString);
* console.log(sanitizedString); // Outputs: This-is-a--sample--string-file-name
*/
export function sanitizeFilename(str) {
return sanitize(str);
}
/**
* Checks if the input string contains only alphabetic characters.
*
* @function
* @export
* @param {string} str - The input string to be checked.
* @returns {boolean} Returns true if the string only contains alphabetic characters (either lower case or upper case), and false if the string contains any non-alphabetic characters.
*
* @example
*
* isAlphabetic("HelloWorld"); // returns true
* isAlphabetic("123ABC"); // returns false
* isAlphabetic("Hello World!"); // returns false
*/
export function isAlphabetic(str) {
const regex = /^[A-Za-z]+$/;
return regex.test(str);
}
/**
* Checks if a string contains only characters valid in filenames
*
* @param {string} str - The input string that needs to be checked.
* @returns {boolean} - Returns `true` if the string is valid
*
* @example
* const isValid = isValidFilename("abc-123"); // Outputs: true
*/
export function isValidFilename(str) {
str = str.trim();
if (str.length === 0)
return false;
// Based on https://superuser.com/a/358861
const regex = /[\\\/:*?"<>|]/;
return !regex.test(str);
}
/**
* Checks if a string contains only numeric characters.
*
* @param {string} str - The input string that needs to be checked.
* @returns {boolean} - Returns `true` if the string is numeric, otherwise returns `false`.
*
* @example
* const isNum = isNumeric("12345"); // Outputs: true
*/
export function isNumeric(str) {
const regex = /^[0-9]+$/;
return regex.test(str);
}
// export const skipSymbol = Symbol('skip');
// export const createSymbol = Symbol('createSymbol');
export const notEmpty = (value) => value !== null && value !== undefined;
export const truncateText = (str, maxLength = MAX_CHARACTERS_LENGTH) => str.length > maxLength ? `${str.substring(0, maxLength - 3)}...` : str;
export const maskStringPreservingStartAndEnd = (str, maxLength = 15, maskChar = '.', maskCharLength = 4) => {
if (str.length <= maxLength) {
return str;
}
else {
const startChars = str.substring(0, (maxLength - maskCharLength) / 2);
const endChars = str.substring(str.length - (maxLength - maskCharLength) / 2);
return `${startChars}${maskChar.repeat(maskCharLength)}${endChars}`;
}
};
export const isNotEmptyString = (value) => value !== null && value !== undefined && value !== '';
export const isNotEmptyObject = (obj) => obj !== undefined && obj !== null && Object.keys(obj).length > 0;
/**
* Prints zod error issues in format
* ```code
* {key}: [issues by key]\n
* ...repeat
* ```
*/
export const formatZodError = (error) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const format = error.format();
const formatted = Object.keys(format)
.map((key) => {
var _a;
if (key === '_errors') {
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
return Array.isArray(format[key]) && format[key].includes('Required')
? 'Can not be empty'
: null;
}
return `${key}: ${(_a = format[key]) === null || _a === void 0 ? void 0 : _a._errors.join(', ')}`;
})
.filter(notEmpty);
return formatted.join('\n');
};
export const safeJsonParse = (value) => {
try {
return JSON.parse(value);
}
catch (e) {
return null;
}
};
export const safeYamlParse = (value) => {
try {
return load(value);
}
catch (e) {
return null;
}
};
export function detectFileParseType(filepath) {
const ext = path.extname(filepath);
if (ext === '.yaml' || ext === '.yml') {
return safeYamlParse;
}
if (ext === '.json') {
return safeJsonParse;
}
return null;
}
export async function loadUnknownFile(filepath) {
const parser = detectFileParseType(filepath);
if (parser === null)
return null;
const file = await services.filesystem.readFile(filepath);
if (file === null)
return null;
return parser(file);
}
export const generateAllChainIds = () => Array.from({ length: MAX_CHAIN_IDS },
// eslint-disable-next-line @typescript-eslint/naming-convention
(_, index) => index.toString());
/**
* Extracts the public key from a given account string.
*
* @param {string} account - The account string in the format `[kctwu]:[a-zA-Z0-9]{64}`.
*
* @returns {string} - The extracted public key from the account.
*
* @throws {Error} - Throws an error if the account format is invalid.
*
* @example
* const account = 'k:abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01';
* const pubKey = getPubKeyFromAccount(account);
* console.log(pubKey); // Outputs: abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01
*/
export function getPubKeyFromAccount(account) {
if (!account.toLowerCase().match(/^[kctwu]:[a-zA-Z0-9]{64}$/)) {
throw new Error('Invalid account');
}
const pubKey = account.toLowerCase().slice(2);
return pubKey;
}
//# sourceMappingURL=globalHelpers.js.map