UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

317 lines (316 loc) 10.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.logger = exports.Logger = exports.LogLevel = exports.DEFAULT_LOG_LEVEL = exports.LOG_LEVELS = void 0; exports.createServerLogger = createServerLogger; const console = __importStar(require("node:console")); const fs_1 = __importDefault(require("fs")); const config_1 = require("./config"); exports.LOG_LEVELS = ['error', 'warning', 'info', 'debug', 'log', '']; exports.DEFAULT_LOG_LEVEL = 'log'; exports.LogLevel = { error: 1, warning: 2, info: 3, debug: 4, log: 5, '': 6, }; function getLogLevel(level) { if (exports.LOG_LEVELS.includes(level)) { return level; } return exports.DEFAULT_LOG_LEVEL; } class Logger { _console = console; _silence = false; _clear = true; _logQueue = []; logFilePath = ''; started = false; isConnectedToConnection = false; requiresConnectionConsole = true; _logLevel = ''; constructor(logFilePath = '') { this.logFilePath = logFilePath; this.log = this.log.bind(this); this.debug = this.debug.bind(this); this.info = this.info.bind(this); this.warning = this.warning.bind(this); this.error = this.error.bind(this); this._log = this._log.bind(this); this.convertArgsToString = this.convertArgsToString.bind(this); this._logWithSeverity = this._logWithSeverity.bind(this); this.logAsJson = this.logAsJson.bind(this); this.logFallbackToStdout = this.logFallbackToStdout.bind(this); } setLogFilePath(logFilePath) { this.logFilePath = logFilePath; return this; } setConnectionConsole(_console) { if (_console) { this._console = _console; this.isConnectedToConnection = true; } return this; } setConsole(_console) { if (_console) { this._console = _console; } return this; } setClear(clear = true) { this._clear = clear; return this; } setSilent(silence = true) { this._silence = silence; return this; } setLogLevel(level) { const logLevel = getLogLevel(level); if (exports.LOG_LEVELS.includes(logLevel)) { this._logLevel = logLevel; } return this; } allowDefaultConsole() { this.requiresConnectionConsole = false; return this; } isConnectionConsole() { return this.isConnectedToConnection; } isStarted() { return this.started; } isSilent() { return this._silence; } isClearing() { return this._clear; } isConnected() { return this.isConnectedToConnection && this.requiresConnectionConsole; } hasLogLevel() { return this._logLevel !== ''; } hasConsole() { if (this.isConnectionConsole()) { return this.isConnected(); } return this._console !== undefined; } start() { this.started = true; this.clearLogFile(); this._logQueue.forEach((message) => { this._log(message); }); return this; } hasLogFile() { return this.logFilePath !== ''; } clearLogFile() { if (this.isClearing() && this.hasLogFile()) { try { fs_1.default.writeFileSync(this.logFilePath, ''); } catch (error) { this._console.error(`Error clearing log file: ${error}`); } } } convertArgsToString(...args) { if (!args || args.length === 0) { return ''; } const formattedArgs = args.map(arg => this.formatArgument(arg)); return formattedArgs.length === 1 ? formattedArgs.at(0) || '' : formattedArgs.join('\n'); } formatArgument(arg) { if (arg === null) return 'null'; if (arg === undefined) return 'undefined'; if (arg instanceof Error) { return arg.stack || arg.message || String(arg); } if (typeof arg === 'string') return arg; if (typeof arg !== 'object') return String(arg); if (arg instanceof Date) { return arg.toISOString(); } if (Array.isArray(arg)) { if (arg.length === 0) return '[]'; if (arg.length < 5 && arg.every(item => item === null || item === undefined || typeof item !== 'object')) { return JSON.stringify(arg); } } try { const seen = new WeakSet(); return JSON.stringify(arg, (key, value) => { if (typeof value === 'function') { return '[Function]'; } if (value instanceof RegExp) { return value.toString(); } if (typeof value === 'object' && value !== null) { if (seen.has(value)) { return '[Circular Reference]'; } seen.add(value); } return value; }, 2); } catch (err) { try { const className = arg.constructor?.name || 'Object'; const properties = Object.keys(arg).length > 0 ? `with ${Object.keys(arg).length} properties` : 'empty'; return `[${className}: ${properties}]`; } catch { return '[Object: stringify failed]'; } } } _log(...args) { if (!args) return; if (!this.isSilent() && this.hasConsole()) this._console.log(...args); const formattedMessage = this.convertArgsToString(...args); if (this.hasLogFile()) { fs_1.default.appendFileSync(this.logFilePath, formattedMessage + '\n', 'utf-8'); } else { this._logQueue.push(formattedMessage); } } logAsJson(...args) { if (!args || args.some(arg => !arg)) return; const formattedMessage = this.convertArgsToString(args); this._log({ date: new Date().toLocaleString(), message: formattedMessage, }); } _logWithSeverity(severity, ...args) { if (this.hasLogLevel() && exports.LogLevel[this._logLevel] < exports.LogLevel[severity]) { return; } const formattedMessage = [severity.toUpperCase() + ':', this.convertArgsToString(...args)].join(' '); this._log(formattedMessage); } logPropertiesForEachObject(objs, ...keys) { objs.forEach((obj, i) => { const selectedKeys = keys.filter(key => Object.prototype.hasOwnProperty.bind(obj, key)); const selectedObj = selectedKeys.reduce((acc, key) => { acc[key] = obj[key]; return acc; }, {}); const formattedMessage = `${i}: ${JSON.stringify(selectedObj, null, 2)}`; this._log(formattedMessage); }); } logTime(...args) { const formattedMessage = this.convertArgsToString(...args); const time = new Date().toLocaleTimeString(); this._log(`[${time}] ${formattedMessage}`); } log(...args) { if (!args) return; const formattedMessage = this.convertArgsToString(...args); if (!this.hasLogLevel()) { this._log(formattedMessage); return; } this._logWithSeverity('log', formattedMessage); } debug(...args) { this._logWithSeverity('debug', ...args); } info(...args) { this._logWithSeverity('info', ...args); } warning(...args) { this._logWithSeverity('warning', ...args); } error(...args) { this._logWithSeverity('error', ...args); } logToStdout(message, newline = true) { const newlineChar = newline ? '\n' : ''; const output = `${message}${newlineChar}`; process.stdout.write(output); } logToStdoutJoined(...message) { const output = `${message.join('')}\n`; process.stdout.write(output); } logToStderr(message, newline = true) { const output = `${message}${!!newline && '\n'}`; process.stderr.write(output); } logFallbackToStdout(...args) { if (this.isStarted()) { this.log(...args); } else { this.logToStdout(JSON.stringify(args, null, 2), true); } } } exports.Logger = Logger; exports.logger = new Logger(); function createServerLogger(logFilePath, connectionConsole) { return exports.logger .setLogFilePath(logFilePath) .setConnectionConsole(connectionConsole) .setSilent() .setLogLevel(config_1.config.fish_lsp_log_level) .start(); }