@visulima/ansi
Version:
ANSI escape codes for some terminal swag.
343 lines (333 loc) • 10.9 kB
JavaScript
'use strict';
const process$2 = require('node:process');
const _interopDefaultCompat = e => e && typeof e === 'object' && 'default' in e ? e.default : e;
const process__default = /*#__PURE__*/_interopDefaultCompat(process$2);
var __defProp$2 = Object.defineProperty;
var __name$2 = (target, value) => __defProp$2(target, "name", { value, configurable: true });
const copyProperty = /* @__PURE__ */ __name$2((to, from, property, ignoreNonConfigurable) => {
if (property === "length" || property === "prototype") {
return;
}
if (property === "arguments" || property === "caller") {
return;
}
const toDescriptor = Object.getOwnPropertyDescriptor(to, property);
const fromDescriptor = Object.getOwnPropertyDescriptor(from, property);
if (!canCopyProperty(toDescriptor, fromDescriptor) && ignoreNonConfigurable) {
return;
}
Object.defineProperty(to, property, fromDescriptor);
}, "copyProperty");
const canCopyProperty = /* @__PURE__ */ __name$2(function(toDescriptor, fromDescriptor) {
return toDescriptor === void 0 || toDescriptor.configurable || toDescriptor.writable === fromDescriptor.writable && toDescriptor.enumerable === fromDescriptor.enumerable && toDescriptor.configurable === fromDescriptor.configurable && (toDescriptor.writable || toDescriptor.value === fromDescriptor.value);
}, "canCopyProperty");
const changePrototype = /* @__PURE__ */ __name$2((to, from) => {
const fromPrototype = Object.getPrototypeOf(from);
if (fromPrototype === Object.getPrototypeOf(to)) {
return;
}
Object.setPrototypeOf(to, fromPrototype);
}, "changePrototype");
const wrappedToString = /* @__PURE__ */ __name$2((withName, fromBody) => `/* Wrapped ${withName}*/
${fromBody}`, "wrappedToString");
const toStringDescriptor = Object.getOwnPropertyDescriptor(Function.prototype, "toString");
const toStringName = Object.getOwnPropertyDescriptor(Function.prototype.toString, "name");
const changeToString = /* @__PURE__ */ __name$2((to, from, name) => {
const withName = name === "" ? "" : `with ${name.trim()}() `;
const newToString = wrappedToString.bind(null, withName, from.toString());
Object.defineProperty(newToString, "name", toStringName);
const { writable, enumerable, configurable } = toStringDescriptor;
Object.defineProperty(to, "toString", { value: newToString, writable, enumerable, configurable });
}, "changeToString");
function mimicFunction(to, from, { ignoreNonConfigurable = false } = {}) {
const { name } = to;
for (const property of Reflect.ownKeys(from)) {
copyProperty(to, from, property, ignoreNonConfigurable);
}
changePrototype(to, from);
changeToString(to, from, name);
return to;
}
__name$2(mimicFunction, "mimicFunction");
var __defProp$1 = Object.defineProperty;
var __name$1 = (target, value) => __defProp$1(target, "name", { value, configurable: true });
const calledFunctions = /* @__PURE__ */ new WeakMap();
const onetime = /* @__PURE__ */ __name$1((function_, options = {}) => {
if (typeof function_ !== "function") {
throw new TypeError("Expected a function");
}
let returnValue;
let callCount = 0;
const functionName = function_.displayName || function_.name || "<anonymous>";
const onetime2 = /* @__PURE__ */ __name$1(function(...arguments_) {
calledFunctions.set(onetime2, ++callCount);
if (callCount === 1) {
returnValue = function_.apply(this, arguments_);
function_ = void 0;
} else if (options.throw === true) {
throw new Error(`Function \`${functionName}\` can only be called once`);
}
return returnValue;
}, "onetime");
mimicFunction(onetime2, function_);
calledFunctions.set(onetime2, callCount);
return onetime2;
}, "onetime");
onetime.callCount = (function_) => {
if (!calledFunctions.has(function_)) {
throw new Error(`The given function \`${function_.name}\` is not wrapped by the \`onetime\` package`);
}
return calledFunctions.get(function_);
};
const signals = [];
signals.push("SIGHUP", "SIGINT", "SIGTERM");
if (process.platform !== "win32") {
signals.push(
"SIGALRM",
"SIGABRT",
"SIGVTALRM",
"SIGXCPU",
"SIGXFSZ",
"SIGUSR2",
"SIGTRAP",
"SIGSYS",
"SIGQUIT",
"SIGIOT"
// should detect profiler and enable/disable accordingly.
// see #21
// 'SIGPROF'
);
}
if (process.platform === "linux") {
signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT");
}
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
const processOk = /* @__PURE__ */ __name((process2) => !!process2 && true && typeof process2.removeListener === "function" && typeof process2.emit === "function" && typeof process2.reallyExit === "function" && typeof process2.listeners === "function" && typeof process2.kill === "function" && typeof process2.pid === "number" && typeof process2.on === "function", "processOk");
const kExitEmitter = Symbol.for("signal-exit emitter");
const global = globalThis;
const ObjectDefineProperty = Object.defineProperty.bind(Object);
class Emitter {
static {
__name(this, "Emitter");
}
emitted = {
afterExit: false,
exit: false
};
listeners = {
afterExit: [],
exit: []
};
count = 0;
id = Math.random();
constructor() {
if (global[kExitEmitter]) {
return global[kExitEmitter];
}
ObjectDefineProperty(global, kExitEmitter, {
value: this,
writable: false,
enumerable: false,
configurable: false
});
}
on(ev, fn) {
this.listeners[ev].push(fn);
}
removeListener(ev, fn) {
const list = this.listeners[ev];
const i = list.indexOf(fn);
if (i === -1) {
return;
}
if (i === 0 && list.length === 1) {
list.length = 0;
} else {
list.splice(i, 1);
}
}
emit(ev, code, signal) {
if (this.emitted[ev]) {
return false;
}
this.emitted[ev] = true;
let ret = false;
for (const fn of this.listeners[ev]) {
ret = fn(code, signal) === true || ret;
}
if (ev === "exit") {
ret = this.emit("afterExit", code, signal) || ret;
}
return ret;
}
}
class SignalExitBase {
static {
__name(this, "SignalExitBase");
}
}
const signalExitWrap = /* @__PURE__ */ __name((handler) => {
return {
onExit(cb, opts) {
return handler.onExit(cb, opts);
},
load() {
return handler.load();
},
unload() {
return handler.unload();
}
};
}, "signalExitWrap");
class SignalExitFallback extends SignalExitBase {
static {
__name(this, "SignalExitFallback");
}
onExit() {
return () => {
};
}
load() {
}
unload() {
}
}
class SignalExit extends SignalExitBase {
static {
__name(this, "SignalExit");
}
// "SIGHUP" throws an `ENOSYS` error on Windows,
// so use a supported signal instead
/* c8 ignore start */
#hupSig = process$1.platform === "win32" ? "SIGINT" : "SIGHUP";
/* c8 ignore stop */
#emitter = new Emitter();
#process;
#originalProcessEmit;
#originalProcessReallyExit;
#sigListeners = {};
#loaded = false;
constructor(process2) {
super();
this.#process = process2;
this.#sigListeners = {};
for (const sig of signals) {
this.#sigListeners[sig] = () => {
const listeners = this.#process.listeners(sig);
let { count } = this.#emitter;
const p = process2;
if (typeof p.__signal_exit_emitter__ === "object" && typeof p.__signal_exit_emitter__.count === "number") {
count += p.__signal_exit_emitter__.count;
}
if (listeners.length === count) {
this.unload();
const ret = this.#emitter.emit("exit", null, sig);
const s = sig === "SIGHUP" ? this.#hupSig : sig;
if (!ret)
process2.kill(process2.pid, s);
}
};
}
this.#originalProcessReallyExit = process2.reallyExit;
this.#originalProcessEmit = process2.emit;
}
onExit(cb, opts) {
if (!processOk(this.#process)) {
return () => {
};
}
if (this.#loaded === false) {
this.load();
}
const ev = opts?.alwaysLast ? "afterExit" : "exit";
this.#emitter.on(ev, cb);
return () => {
this.#emitter.removeListener(ev, cb);
if (this.#emitter.listeners["exit"].length === 0 && this.#emitter.listeners["afterExit"].length === 0) {
this.unload();
}
};
}
load() {
if (this.#loaded) {
return;
}
this.#loaded = true;
this.#emitter.count += 1;
for (const sig of signals) {
try {
const fn = this.#sigListeners[sig];
if (fn)
this.#process.on(sig, fn);
} catch (_) {
}
}
this.#process.emit = (ev, ...a) => {
return this.#processEmit(ev, ...a);
};
this.#process.reallyExit = (code) => {
return this.#processReallyExit(code);
};
}
unload() {
if (!this.#loaded) {
return;
}
this.#loaded = false;
signals.forEach((sig) => {
const listener = this.#sigListeners[sig];
if (!listener) {
throw new Error("Listener not defined for signal: " + sig);
}
try {
this.#process.removeListener(sig, listener);
} catch (_) {
}
});
this.#process.emit = this.#originalProcessEmit;
this.#process.reallyExit = this.#originalProcessReallyExit;
this.#emitter.count -= 1;
}
#processReallyExit(code) {
if (!processOk(this.#process)) {
return 0;
}
this.#process.exitCode = code || 0;
this.#emitter.emit("exit", this.#process.exitCode, null);
return this.#originalProcessReallyExit.call(this.#process, this.#process.exitCode);
}
#processEmit(ev, ...args) {
const og = this.#originalProcessEmit;
if (ev === "exit" && processOk(this.#process)) {
if (typeof args[0] === "number") {
this.#process.exitCode = args[0];
}
const ret = og.call(this.#process, ev, ...args);
this.#emitter.emit("exit", this.#process.exitCode, null);
return ret;
} else {
return og.call(this.#process, ev, ...args);
}
}
}
const process$1 = globalThis.process;
const {
/**
* Called when the process is exiting, whether via signal, explicit
* exit, or running out of stuff to do.
*
* If the global process object is not suitable for instrumentation,
* then this will be a no-op.
*
* Returns a function that may be used to unload signal-exit.
*/
onExit} = signalExitWrap(processOk(process$1) ? new SignalExit(process$1) : new SignalExitFallback());
const terminal = process__default.stderr.isTTY ? process__default.stderr : process__default.stdout.isTTY ? process__default.stdout : void 0;
const restoreCursor = terminal ? onetime(() => {
onExit(() => {
terminal.write("\x1B[?25h");
}, { alwaysLast: true });
}) : () => {
};
module.exports = restoreCursor;