const path = require("path");
const url = require('url');
const fs = require('fs');
const { get_random, MAID_EMOJIS } = require("./constants");
const DEBUG = false;
const { marked } = require('marked'); //Formats into html
var TerminalRenderer = require('marked-terminal'); //Formats into terminal
const { exec } = require('child_process');
marked.setOptions(
{
renderer: new TerminalRenderer(),
}
)
/**
* Gets clickeable path that could be printed on the console and clicked.
* @param {str} fileimage : String containing the relative position of the image from utils directory
* @returns {str} Formatted file:///C:/github/testing/mastery-cli/img/unicorn.png
*/
const getAbsoluteUri = (fileimage = './img/unicorn.png', subdirectory = './data/') => {
// Note it should take from the root.
const absolutePath = path.resolve(path.join(__dirname, './data/', fileimage)); // Note the '../' because it is inside of constants
const fileUrl = url.pathToFileURL(absolutePath);
return (fileUrl.toString());
};
/**
* Gets directory path
* @param {str} fileimage : String containing the relative position of the image from utils directory
* @returns {str} Formatted C:/github/testing/mastery-cli/img/unicorn.png
*/
const getDirAbsoluteUri = (fileimage = './img/unicorn.png', subdirectory = './data/') => {
// Note it should take from the root.
const absolutePath = path.resolve(path.join(__dirname, './data/', fileimage)); // Note the '../' because it is inside of constants
// const fileUrl = url.pathToFileURL(abosolutePath);
return (absolutePath.toString());
};
/**
*
* @param {string} directoryPath './data/priorities'
* @returns Promise that resolves to the files in the directory
*/
const getFilesInDirectory = (directoryPath = './data/priorities') => {
const absolutePath = path.resolve(path.join(__dirname, directoryPath));
if (DEBUG) console.log("Fetching from: ", absolutePath);
return new Promise((resolve, reject) => {
fs.readdir(absolutePath, (err, files) => {
if (err) {
reject(err);
} else {
resolve(files);
}
});
});
}
/**
* Return the absolute path of the codebase
* @returns {str} Formatted full Directory of the codebase e.g. C:/github/testing/mastery-cli
*/
const getMaidDirectory = () => {
// Note it should take from the root.
const absolutePath = path.resolve(path.join(__dirname, '../'));
return (absolutePath.toString());
};
/**
* Shows an image, if it is a url then it will fetch it, otherwise it will read it from the local file
* @param {string} image_file Image of the file to show
* @param {is_url} is_url Whether the image is a url or not
*/
async function show_image(image_file, { is_url = false } = {}) {
// let ima
let image_file_dir = is_url ? image_file : getDirAbsoluteUri(image_file);
try {
if (is_url) {
const { default: terminalImage } = await import('terminal-image');
const {default: fetch} = await import('node-fetch');
const response = await fetch(image_file_dir);
const buffer = await response.arrayBuffer();
const image = await terminalImage.buffer(Buffer.from(buffer));
console.log(image);
} else {
//If it is not url, finds the absolute path of the local file
const fs = await import('fs').then((mod) => mod.promises);
const { default: terminalImage } = await import('terminal-image');
// console.log("reading from path: " + image_file_dir)node
const data = await fs.readFile(image_file_dir);
const image = await terminalImage.buffer(data);
console.log(image);
}
}
catch (err) {
console.log("Error while attempting to fetch image", err, image_file_dir);
}
};
/**
* Prints the image if it is a url
*/
async function show_image_if_isurl(message) {
// check if is url if not, then just print the message
let is_url = message.startsWith("http"); // Includes https
try {
if (is_url) {
const { default: terminalImage } = await import('terminal-image');
const {default: fetch} = await import('node-fetch');
const response = await fetch(image_file_dir);
const buffer = await response.arrayBuffer();
const image = await terminalImage.buffer(Buffer.from(buffer));
console.log(image);
} else {
console.log(message)
}
}
catch (err) {
console.log("Error while attempting to fetch image", err, image_file_dir);
}
};
// https://api.apilayer.com/exchangerates_data/convert?to={to}&from={from}&amount={amount}
const getRandomMaidEmoji = () => {
return `:${get_random(MAID_EMOJIS)}:`;
};
const appendQuotes = (message) => {
return `"${message}"`;
};
const formatLastTwoDecimals = (original) => {
return (Math.round(original * 100) / 100);
};
const formatObjectFeatures = (userPerformanceData) => {
for (const feat of Object.keys(userPerformanceData)) {
userPerformanceData[feat] = formatLastTwoDecimals(userPerformanceData[feat]);
}
return userPerformanceData;
};
const getRandomInt = (max) => {
return Math.floor(Math.random() * max);
};
/**
* @param: float ?= 0.05 #e.g. 0.5 The chances in favor of it being True
* @returns Random Bool
*/
const getRandomBool = (chances = 0.5) => {
return random_boolean = Math.random() < chances;
};
/**
* Counts the decimals.
* @param {number} value Number to count decimals
* @returns {number} Number of decimals
*/
const countDecimals = (value) => {
if (Math.floor(value) !== value)
return value?.toString().split(".")[1].length ?? 0;
return 0;
};
/**
* Returns whether the user wants to exit.
* @param {str} res : User input
* @returns {boolean} : True if user wants to exit, false otherwise
*/
const user_requests_exit = (res) => {
return (res == "exit" || res == "quit" || res == "q" || res == "!")
}
/**
* Returns whether the user wants to open a calculator node. (for now a js node would work.)
* @param {str} res : User input
* @returns {boolean} : True if user wants to calculate, false otherwise
*/
const user_requests_calc = (res) => {
return (res == "calc")
}
/**
* Returns whether the user wants to skip the problem.
* @param {boolean} res : User input
* @returns {boolean} : True if user wants to skip, false otherwise
*/
const user_requests_skip = (res) => {
return (res == "skip" || res == "s" || res == "next" || res == "n" || res == "no" || res == "")
}
/**
* Prints the content as markdown if it is markdown, otherwise it will just print the content
* @param {string} content The String content that can be either markdown or not, determined by :m
* @param {boolean} use_markdown If true then it will use markdown, if false then it will just print the content
* @param {string} markdown_token The token that determines if the content is markdown or not
*/
function printMarked(content, { use_markdown = true, markdown_token = ":m" } = {}) {
if (use_markdown) {
// Check if the description starts with :m
if (content.startsWith(markdown_token)) {
if (DEBUG)
console.log("markdown detected");
// Remove the :m
content = content.substring(2);
console.log(marked(content));
} else {
console.log(`${content}\n`);
}
} else {
console.log(`${content}\n`);
}
}
/**
* Open the editor with the given instruction
* @param {Awaited<void>} Returns once the editor is closed
*/
const openEditorWithCommand = async (instruction) => {
await exec(`${instruction}`, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`Continue running`);
});
}
/**
* Opens the editor with the given instruction and the absolute path of the file
* @param {string} editor_instruction e.g. code, vim, nano, etc.
* @param {string} absolute_temp_file_path e.g. /home/username/.../temp.js
*/
const openEditorPlatformAgnostic = async (editor_instruction, {absolute_temp_file_path = ""} = {}) => {
const os = require('os');
if (os.platform() === 'win32') {
console.log('Windows');
await openEditorWithCommand(`start ${editor_instruction} ${absolute_temp_file_path}`);
} else if (os.platform() === 'linux') {
console.log('Linux');
await openEditorWithCommand(`${editor_instruction} ${absolute_temp_file_path}`);
} else if (os.platform() === 'darwin') {
console.log('macOS');
await openEditorWithCommand(`open -a ${editor_instruction} ${absolute_temp_file_path}`);
} else {
console.log('Unknown operating system');
await openEditorWithCommand(`${editor_instruction} ${absolute_temp_file_path}`);
}
}
module.exports = {
getAbsoluteUri, getDirAbsoluteUri, getRandomMaidEmoji, appendQuotes, formatObjectFeatures, getRandomInt,
getRandomBool, countDecimals, show_image, getMaidDirectory, getFilesInDirectory, user_requests_exit,
user_requests_skip, user_requests_calc, printMarked, openEditorPlatformAgnostic, show_image_if_isurl
};