import * as fs from "fs";
import { exec } from "child_process";
import * as path from "path";
import { dirname } from "path";
import * as Process from "process";
import { localStorage } from "../node-localstorage/index";
//const { promisify } = require("util");
import { promisify } from "util";
import observatory from "../observatory/lib/observatory";
import chalk from "chalk";
import dns from "dns";
import sorter from "./sorter";
/**
* Check connectivity
*/
export function isOffline() {
let res = null;
dns.resolve("www.google.com", function (err) {
if (err) {
res = true;
} else {
res = false;
}
});
return res;
}
/**
* Locate asset file
* @param file
*/
export function asset(file: string) {
file = file.toString().trim().replace(/\.\//gm, "");
if (fs.existsSync(file)) {
return file;
} else if (fs.existsSync(`./${file}`)) {
return `./${file}`;
} else if (fs.existsSync(path.join(Process.cwd(), file))) {
return path.join(Process.cwd(), file);
}
}
/**
* Smart read file
* @param file
*/
export function readFile(file: string) {
if (fs.existsSync(file)) {
return fs.readFileSync(file).toString();
}
return `${file} not found`;
}
/**
* write package
* @param packageObject
*/
export function writenow(packageObject: packagejson) {
const sorterFound = trycatch(function () {
return true;
});
if (packageObject && typeof packageObject == "object" && count(packageObject) > 0) {
if (sorterFound) {
fs.writeFileSync(path.join(__dirname, "package.json"), JSON.stringify(sorter.reorder(packageObject), null, 4), {
encoding: "utf-8",
});
} else {
console.log("sorter not found, using default...");
fs.writeFileSync(path.join(__dirname, "package.json"), JSON.stringify(packageObject, null, 4), {
encoding: "utf-8",
});
}
} else {
console.warn("not object", typeof packageObject);
}
}
export function random_hex(familiar?: boolean) {
if (familiar) {
const choose = {
aqua: "#00ffff",
azure: "#f0ffff",
beige: "#f5f5dc",
black: "#000000",
blue: "#0000ff",
brown: "#a52a2a",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgrey: "#a9a9a9",
darkgreen: "#006400",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkviolet: "#9400d3",
fuchsia: "#ff00ff",
gold: "#ffd700",
green: "#008000",
indigo: "#4b0082",
khaki: "#f0e68c",
lightblue: "#add8e6",
lightcyan: "#e0ffff",
lightgreen: "#90ee90",
lightgrey: "#d3d3d3",
lightpink: "#ffb6c1",
lightyellow: "#ffffe0",
lime: "#00ff00",
magenta: "#ff00ff",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
orange: "#ffa500",
pink: "#ffc0cb",
purple: "#800080",
violet: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
white: "#ffffff",
yellow: "#ffff00",
};
const values = Object.values(choose);
return values[Math.floor(Math.random() * values.length)];
} else {
return "#" + (0x1000000 + Math.random() * 0xffffff).toString(16).substr(1, 6);
}
}
/**
* Write file recursive
* @param path
* @param contents
* @param cb
*/
export function writeFile(
path: string | number | Buffer | import("url").URL,
contents: any,
cb?: { (arg0: any): any; (err: NodeJS.ErrnoException): void }
) {
try {
contents = JSON.parse(contents.toString());
} catch (error) {
}
if (typeof contents == "object" || Array.isArray(contents)) {
contents = JSON.stringify(contents, null, 2);
}
resolve_dir(dirname(path.toString()));
if (typeof contents == "string") {
if (fs.existsSync(dirname(path.toString()))) {
if (typeof cb == "function") {
fs.writeFile(path.toString(), contents.toString(), cb);
} else {
fs.writeFileSync(path.toString(), contents.toString());
}
return true;
}
}
console.error(`contents must be type string, instead of ${typeof contents}`);
return false;
}
/**
* Resolve directory, create if not exists
* @param path
*/
export function resolve_dir(path: string) {
if (!fs.existsSync(dirname(path.toString()))) {
resolve_dir(dirname(path.toString()));
}
if (!fs.existsSync(path.toString())) {
fs.mkdirSync(path.toString());
}
}
/**
* Random RGB color
*/
export function random_rgba() {
const o = Math.round,
r = Math.random,
s = 255;
return "rgba(" + o(r() * s) + "," + o(r() * s) + "," + o(r() * s) + "," + r().toFixed(1) + ")";
}
/**
* Fix dependencies and devDependencies
* @param pkg
*/
export async function fixDeps(pkg: packagejson) {
const ori = pkg;
if (!pkg.hasOwnProperty("dependencies")) {
console.error("package.json does not have dependencies");
throw pkg;
}
for (const key in pkg.dependencies) {
if (pkg.dependencies.hasOwnProperty(key)) {
const version = pkg.dependencies[key];
const dups = Object.keys(pkg.devDependencies).includes(key);
if (dups) {
console.warn(`${key} duplicate, removing...`);
delete pkg.dependencies[key];
}
if (key.includes("@types")) {
console.warn(`${key} is typehinting module, moving to dev...`);
pkg.devDependencies[key] = version;
delete pkg.dependencies[key];
}
}
}
if (typeof pkg == "object" && Object.keys(pkg).length) {
return pkg;
}
return ori;
}
let execute_is_running = false;
const execute_dump = [];
/**
* Execute command schedule
* @param cmds
* @requires NodeJS
* @param callback
*/
export function execute(cmd: string | null, callback: (arg0: boolean, arg1: string | Error) => any = null): any {
if (typeof cmd != "string") {
console.log(typeof cmd + " not string");
return;
}
if (execute_is_running === false) {
execute_is_running = true;
exec(cmd.trim(), (error, stdout, stderr) => {
setTimeout(function () {
execute_is_running = false;
}, 500);
if (error instanceof Error) {
if (error.hasOwnProperty("code")) {
console.error(error.code);
} else if (error.hasOwnProperty("message")) {
console.error(error.message);
} else {
console.error(error);
}
if (typeof callback == "function") {
if (stdout) {
callback(false, new Error(stdout));
} else if (stderr) {
callback(false, new Error(stderr));
} else {
callback(false, new Error("error"));
}
}
console.error(error);
} else {
if (typeof callback != "function") {
console.log("callback is not function", stdout ? stdout : stderr);
} else {
if (stdout) {
callback(true, stdout);
} else if (stderr) {
callback(false, stderr);
}
}
}
});
} else {
if (execute_dump && !execute_dump.includes(cmd)) {
console.warn("executor still running, please wait");
execute_dump.push(cmd);
}
setTimeout(function () {
execute(cmd, callback);
}, 1000);
}
}
/**
* check if module exists
* @param tmodule
* @requires node
*/
export function module_exists(tmodule: Array<string> | string, global = false, dump = false) {
const test = function (tmodule: string, global: boolean) {
let result = null;
execute(("npm list -json -depth=0 " + (global ? "-g" : "")).trim(), function (error, message) {
if (message instanceof Error || !error) {
result = false;
} else {
try {
const json: npmlist = JSON.parse(message);
result = Object.keys(json.dependencies).includes(tmodule);
if (dump) {
console.log(`${tmodule} is ${result ? "installed" : "not installed"}`);
}
} catch (error) {
result = false;
}
}
});
return result;
};
if (typeof tmodule == "string") {
return test(tmodule, global);
}
const tests = [];
if (Array.isArray(tmodule)) {
tmodule.forEach(function (single) {
tests.push(test(single, global));
});
return tests.every(Boolean) ? true : false;
}
}
/**
* Configuration builder
*/
export function config_builder() {
const config = require(asset("./config.json"));
let parsed = JSON.stringify(parseConfig(config, true), null, 2);
if (fs.existsSync(asset("./libs"))) {
console.error("Libs folder not exists, exiting config builder.");
return null;
}
fs.writeFileSync(asset("./config-backup.json"), parsed, {
encoding: "utf-8",
});
const str = fs
.readFileSync(asset("./libs/src/compiler/config.ts"), {
encoding: "utf-8",
})
.toString()
.replace(/\s|\t/gm, " ");
parsed = JSON.stringify(parseConfig(config, false), null, 2)
.replace(/\"string\"/gm, "string")
.replace(/\"boolean\"/gm, "boolean")
.replace(/\"number\"/gm, "number");
const regex = /config\:((.|\n)*)\=\srequire/gm;
const mod = str.replace(regex, `config:${parsed} = require`);
fs.writeFileSync(asset("./libs/src/compiler/config.ts"), mod);
function parseConfig(config: { [key: string]: any }, usingExclude: boolean = null) {
const excluded = function (key: string) {
return ["vscode"].indexOf(key) == -1;
};
for (const key in config) {
if (config.hasOwnProperty(key)) {
if (!excluded(key) && usingExclude) {
continue;
}
const element = config[key];
const type = typeof element;
if (["number", "string", "boolean"].indexOf(type) != -1) {
config[key] = type;
} else if (type == "object") {
config[key] = parseConfig(config[key]);
} else if (Array.isArray(config[key])) {
config[key].forEach(parseConfig);
}
}
}
return config;
}
}
/**
* Remove source sub elements array if exists in target array
* ```js
* // If I have this array:
* var myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
* // and this one:
* var toRemove = ['b', 'c', 'g'];
* console.log(array_remove(myArray, toRemove)); // => ['a', 'd', 'e', 'f']
* ```
* @param source
* @param target
*/
export function array_remove(source: Array<string>, target: Array<string>) {
return source.filter(function (el) {
return !target.includes(el);
});
}
/**
* Array object counter
* @param objarr
*/
export function count(objarr: any[] | object) {
if (Array.isArray(objarr)) {
return objarr.length;
} else if (typeof objarr == "object") {
return Object.keys(objarr).length;
}
}
/**
* Do trycatch
* @param callback
*/
export function trycatch(callback: () => any) {
try {
const test = callback();
if (typeof test == "boolean") {
return test;
}
return true;
} catch (error) {
return false;
}
}
/**
* Async current function
* @param callback
*/
export function async(callback: Function) {
return new Promise(async function (resolve, reject) {
if (typeof callback == "function") {
await callback();
resolve(true);
} else {
reject(false);
}
});
}
/**
* Get latest version of packages
* @param key
*/
export function getLatestVersion(key: string) {
execute(`npm show ${key} version`, function (error, message) {
if (message instanceof Error || !error) {
console.error(error);
}
try {
writeFile(`./tmp/npm/packages/${key}/latest.json`, JSON.parse(message.toString()));
} catch (error) {
}
});
}
/**
* Async execute commands
* @param commands
* @param callback callback for each command return
*/
export function async_exec(commands: string[], callback: (stdout: string, stderr: string, isLast: boolean) => any) {
if (!Array.isArray(commands)) {
console.error("commands must be instance of array");
return null;
}
const executor = promisify(exec);
const exec2 = async function () {
let script: string;
let index = 0;
for await (script of commands) {
try {
const {stdout, stderr} = await executor(script);
if (typeof callback == "function") {
callback(stdout, stderr, !--commands.length);
}
} catch (e) {
console.error(e);
}
index++;
}
return true;
};
return exec2;
}
localStorage.removeItem("list_package_latest");
localStorage.removeItem("list_package");
/**
* Get list packages and fetch latest version
*/
export function list_package() {
if (isOffline()) {
console.error("Are you offline");
return;
}
if (!localStorage.getItem("list_package")) {
localStorage.setItem("list_package", "true");
const global = exec("npm list -json -depth=0 -g");
global.stdout.on("data", function (data) {
writeFile("./tmp/npm/global.json", data);
});
global.stderr.on("data", function (data) {
writeFile("./tmp/npm/global-error.json", data);
});
const local = exec("npm list -json -depth=0");
local.stdout.on("data", function (data) {
try {
data = JSON.parse(data);
if (fs.existsSync("./tmp/npm/local.json")) {
const old = JSON.parse(fs.readFileSync("./tmp/npm/local.json").toString());
if (old) {
data = Object.assign({}, data, old);
}
}
if (data.hasOwnProperty("dependencies") && !localStorage.getItem("list_package_latest")) {
localStorage.setItem("list_package_latest", "1");
const executor = promisify(exec);
const dependencies = Object.keys(data.dependencies);
const checkLatest = async function () {
//observatory.settings({ prefix: chalk.cyan("[Buzz] ") });
const task = observatory.add("Fetch latest version");
for await (const key of dependencies) {
if (data.dependencies.hasOwnProperty(key)) {
try {
var {stdout} = await executor("npm show " + key + " version");
data.dependencies[key].latest = stdout.trim();
if (!key.includes("@types")) {
var {stdout} = await executor("npm view @types/" + key + " version -json");
if (stdout.trim().length) {
data.dependencies[key].types = {
name: "@types/" + key,
version: stdout.trim(),
};
} else {
data.dependencies[key].types = {
name: null,
version: null,
};
}
}
writeFile("./tmp/npm/local.json", data);
task
.status(
((dependencies.length * 100) / Object.keys(data.dependencies).length).toFixed(3).toString() + "%"
)
.details(chalk.hex(random_hex(true)).underline(key));
} catch (error) {
console.error(error);
}
if (!--dependencies.length) {
localStorage.removeItem("list_package_latest");
task.done("Complete");
}
}
}
};
checkLatest()
.catch(function (err) {
})
.then(function () {
localStorage.removeItem("list_package");
});
}
} catch (error) {
}
});
local.stderr.on("data", function (data) {
writeFile("./tmp/npm/local-error.json", data);
});
} else {
console.warn(
"process for list_package is locked, if previous runner got error, please fix it using `node index.js fix`"
);
}
}
/*
results.local = data;
if (count(results)) {
for (const key in results.local) {
if (results.local.hasOwnProperty(key)) {
const version = results.local[key];
getLatestVersion(key);
}
}
writeFile("./tmp/npm/installed.json", results);
timer_run = null;
}
*/
Source