type-compiler
Version:
A TypeScript compiler plugin for enhanced runtime type checking and analysis with Zod validation
327 lines (326 loc) • 10.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LoggerSchema = exports.LoggerConfigSchema = exports.LogLevelSchema = exports.logger = exports.Logger = exports.LogLevel = void 0;
exports.getLogger = getLogger;
const zod_1 = require("zod");
const typescript_1 = __importDefault(require("typescript"));
/**
* Log levels for the type compiler
*/
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["ERROR"] = 0] = "ERROR";
LogLevel[LogLevel["WARN"] = 1] = "WARN";
LogLevel[LogLevel["INFO"] = 2] = "INFO";
LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG";
LogLevel[LogLevel["TRACE"] = 4] = "TRACE"; // Very verbose logging
})(LogLevel || (exports.LogLevel = LogLevel = {}));
/**
* Default logger configuration
*/
const DEFAULT_CONFIG = {
level: LogLevel.INFO,
useColors: true,
includeTimestamps: true,
logToFile: false
};
/**
* Colors for different log levels when useColors is true
*/
const COLORS = {
[LogLevel.ERROR]: '\x1b[31m', // Red
[LogLevel.WARN]: '\x1b[33m', // Yellow
[LogLevel.INFO]: '\x1b[36m', // Cyan
[LogLevel.DEBUG]: '\x1b[90m', // Gray
[LogLevel.TRACE]: '\x1b[90m', // Gray
RESET: '\x1b[0m'
};
/**
* Logger class for the type compiler
*/
class Logger {
constructor(config = {}) {
this.buffer = [];
this.startTime = Date.now();
this.compilationMetrics = {
typesProcessed: 0,
filesProcessed: 0,
cacheHits: 0,
cacheMisses: 0,
workerTasksProcessed: 0,
errors: 0,
warnings: 0
};
this.config = { ...DEFAULT_CONFIG, ...config };
}
/**
* Reconfigure the logger
*/
configure(config) {
this.config = { ...this.config, ...config };
}
/**
* Configure the logger from TypeCompilerOptions
*/
configureFromOptions(options) {
const level = this.getLogLevelFromOptions(options);
this.configure({ level });
}
/**
* Map TypeCompilerOptions to LogLevel
*/
getLogLevelFromOptions(options) {
if (options.logLevel !== undefined) {
return options.logLevel;
}
// Determine log level based on other options
if (options.debug === true) {
return LogLevel.DEBUG;
}
if (options.verbose === true) {
return LogLevel.INFO;
}
if (options.silent === true) {
return LogLevel.ERROR;
}
return LogLevel.INFO; // Default log level
}
/**
* Log a message at a specific level
*/
log(level, message, context) {
if (level > this.config.level) {
return;
}
if (this.config.filter && !this.config.filter(level, message, context)) {
return;
}
let formattedMessage = '';
// Add timestamp if configured
if (this.config.includeTimestamps) {
const timestamp = new Date().toISOString();
formattedMessage += `[${timestamp}] `;
}
// Add log level indicator
const levelNames = ['ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'];
const levelName = levelNames[level] || 'UNKNOWN';
// Add colors if configured
if (this.config.useColors) {
formattedMessage += `${COLORS[level]}[${levelName}]${COLORS.RESET} `;
}
else {
formattedMessage += `[${levelName}] `;
}
// Add the message
formattedMessage += message;
// Add context if provided
if (context && Object.keys(context).length > 0) {
const contextStr = JSON.stringify(context, null, 2);
formattedMessage += ` ${contextStr}`;
}
// Output to console
if (level === LogLevel.ERROR) {
console.error(formattedMessage);
this.compilationMetrics.errors++;
}
else if (level === LogLevel.WARN) {
console.warn(formattedMessage);
this.compilationMetrics.warnings++;
}
else {
console.log(formattedMessage);
}
// Store in buffer for later retrieval
this.buffer.push(formattedMessage);
// TODO: Log to file if configured
// This would be implemented with Node.js fs functions
}
/**
* Log an error message
*/
error(message, context) {
this.log(LogLevel.ERROR, message, context);
}
/**
* Log a warning message
*/
warn(message, context) {
this.log(LogLevel.WARN, message, context);
}
/**
* Log an info message
*/
info(message, context) {
this.log(LogLevel.INFO, message, context);
}
/**
* Log a debug message
*/
debug(message, context) {
this.log(LogLevel.DEBUG, message, context);
}
/**
* Log a trace message
*/
trace(message, context) {
this.log(LogLevel.TRACE, message, context);
}
/**
* Handle TypeScript diagnostics
*/
logDiagnostics(diagnostics) {
if (diagnostics.length === 0) {
return;
}
this.info(`Found ${diagnostics.length} TypeScript diagnostic messages`);
for (const diagnostic of diagnostics) {
const message = typescript_1.default.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
if (diagnostic.category === typescript_1.default.DiagnosticCategory.Error) {
this.error(message, this.formatDiagnosticLocation(diagnostic));
}
else if (diagnostic.category === typescript_1.default.DiagnosticCategory.Warning) {
this.warn(message, this.formatDiagnosticLocation(diagnostic));
}
else {
this.info(message, this.formatDiagnosticLocation(diagnostic));
}
}
}
/**
* Format diagnostic location information
*/
formatDiagnosticLocation(diagnostic) {
if (!diagnostic.file || diagnostic.start === undefined) {
return undefined;
}
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
return {
file: diagnostic.file.fileName,
line: line + 1,
character: character + 1
};
}
/**
* Update compilation metrics
*/
updateMetrics(metrics) {
Object.assign(this.compilationMetrics, metrics);
}
/**
* Increment a specific metric
*/
incrementMetric(metric, amount = 1) {
if (this.compilationMetrics[metric] !== undefined) {
this.compilationMetrics[metric] += amount;
}
else {
this.compilationMetrics[metric] = amount;
}
}
/**
* Log compilation summary
*/
logCompilationSummary() {
const elapsedTime = (Date.now() - this.startTime) / 1000;
this.info('Compilation completed', {
elapsedTime: `${elapsedTime.toFixed(2)}s`,
...this.compilationMetrics
});
// Log performance information
if (this.compilationMetrics.typesProcessed > 0) {
const typesPerSecond = (this.compilationMetrics.typesProcessed / elapsedTime).toFixed(2);
this.info(`Processed ${this.compilationMetrics.typesProcessed} types (${typesPerSecond} types/sec)`);
}
if (this.compilationMetrics.cacheHits > 0 || this.compilationMetrics.cacheMisses > 0) {
const totalCacheRequests = this.compilationMetrics.cacheHits + this.compilationMetrics.cacheMisses;
const cacheHitRate = (this.compilationMetrics.cacheHits / totalCacheRequests * 100).toFixed(2);
this.info(`Cache hit rate: ${cacheHitRate}% (${this.compilationMetrics.cacheHits} hits, ${this.compilationMetrics.cacheMisses} misses)`);
}
// Log errors and warnings
if (this.compilationMetrics.errors > 0 || this.compilationMetrics.warnings > 0) {
this.info(`Encountered ${this.compilationMetrics.errors} errors and ${this.compilationMetrics.warnings} warnings`);
}
}
/**
* Start timing an operation
*/
startTimer(label) {
const startTime = Date.now();
// Return a function that, when called, will end the timer and log the duration
return () => {
const duration = Date.now() - startTime;
this.debug(`${label} completed in ${duration}ms`);
};
}
/**
* Get the log buffer
*/
getBuffer() {
return [...this.buffer];
}
/**
* Clear the log buffer
*/
clearBuffer() {
this.buffer = [];
}
/**
* Reset compilation metrics
*/
resetMetrics() {
this.startTime = Date.now();
Object.keys(this.compilationMetrics).forEach(key => {
this.compilationMetrics[key] = 0;
});
}
}
exports.Logger = Logger;
// Create a global logger instance with default configuration
exports.logger = new Logger();
// Helper function to get the global logger
function getLogger() {
return exports.logger;
}
exports.LogLevelSchema = z.object({
toString: z.any(),
toFixed: z.any(),
toExponential: z.any(),
toPrecision: z.any(),
valueOf: z.any(),
toLocaleString: z.any()
});
exports.LoggerConfigSchema = z.object({
level: z.any(),
useColors: z.any(),
includeTimestamps: z.any(),
logToFile: z.any(),
logFilePath: z.any(),
filter: z.any()
});
exports.LoggerSchema = z.object({
config: z.any(),
buffer: z.any(),
startTime: z.any(),
compilationMetrics: z.any(),
configure: z.any(),
configureFromOptions: z.any(),
getLogLevelFromOptions: z.any(),
log: z.any(),
error: z.any(),
warn: z.any(),
info: z.any(),
debug: z.any(),
trace: z.any(),
logDiagnostics: z.any(),
formatDiagnosticLocation: z.any(),
updateMetrics: z.any(),
incrementMetric: z.any(),
logCompilationSummary: z.any(),
startTimer: z.any(),
getBuffer: z.any(),
clearBuffer: z.any(),
resetMetrics: z.any()
});