UNPKG

type-compiler

Version:

A TypeScript compiler plugin for enhanced runtime type checking and analysis with Zod validation

235 lines (234 loc) 8.75 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 () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.FileCacheSchema = exports.FileCache = exports.globalTypeCache = void 0; exports.getFileCache = getFileCache; exports.isFileUnchanged = isFileUnchanged; exports.markFileAsProcessed = markFileAsProcessed; const zod_1 = require("zod"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const crypto = __importStar(require("crypto")); const logger_1 = require("./logger"); /** * Global cache to store computed Zod schemas across transformer invocations */ exports.globalTypeCache = new Map(); /** * File cache for tracking file modifications for incremental compilation */ class FileCache { constructor(cachePath) { this.cache = new Map(); this.initialized = false; this.cachePath = cachePath; this.initialized = false; this.loadCache(); } /** * Load the cache from disk if a cache path is provided */ loadCache() { if (this.initialized) return; if (this.cachePath && fs.existsSync(this.cachePath)) { try { logger_1.logger.debug(`Loading cache from ${this.cachePath}`); const cacheData = JSON.parse(fs.readFileSync(this.cachePath, 'utf-8')); for (const [key, value] of Object.entries(cacheData)) { this.cache.set(key, value); } logger_1.logger.info(`Loaded ${this.cache.size} entries from cache`); } catch (error) { logger_1.logger.error('Error loading cache', { error: error instanceof Error ? error.message : String(error), path: this.cachePath }); // Continue without cache if there's an error } } else if (this.cachePath) { logger_1.logger.debug(`Cache file does not exist yet: ${this.cachePath}`); } this.initialized = true; } /** * Save the cache to disk if a cache path is provided */ saveCache() { if (!this.cachePath) return; try { logger_1.logger.debug(`Saving cache to ${this.cachePath}`); const cacheData = {}; for (const [key, value] of this.cache.entries()) { cacheData[key] = value; } // Create directory if it doesn't exist const cacheDir = path.dirname(this.cachePath); if (!fs.existsSync(cacheDir)) { fs.mkdirSync(cacheDir, { recursive: true }); } fs.writeFileSync(this.cachePath, JSON.stringify(cacheData, null, 2)); logger_1.logger.info(`Saved ${this.cache.size} entries to cache`); } catch (error) { logger_1.logger.error('Error saving cache', { error: error instanceof Error ? error.message : String(error), path: this.cachePath }); // Continue even if we can't save the cache } } /** * Check if a file has changed since the last time it was processed */ hasFileChanged(filePath) { try { if (!fs.existsSync(filePath)) { // File doesn't exist, so consider it changed logger_1.logger.debug(`File does not exist: ${filePath}`); return true; } const stats = fs.statSync(filePath); const currentTimestamp = stats.mtimeMs; // Compute a hash of the file content const fileContent = fs.readFileSync(filePath, 'utf-8'); const contentHash = crypto .createHash('md5') .update(fileContent) .digest('hex'); const cachedInfo = this.cache.get(filePath); if (!cachedInfo) { // File not in cache, so consider it changed logger_1.logger.trace(`File not in cache: ${filePath}`); this.updateFile(filePath, currentTimestamp, contentHash); logger_1.logger.incrementMetric('cacheMisses'); return true; } // Check if timestamp or content has changed if (cachedInfo.timestamp !== currentTimestamp || cachedInfo.contentHash !== contentHash) { logger_1.logger.trace(`File has changed: ${filePath}`); this.updateFile(filePath, currentTimestamp, contentHash); logger_1.logger.incrementMetric('cacheMisses'); return true; } logger_1.logger.trace(`File unchanged: ${filePath}`); logger_1.logger.incrementMetric('cacheHits'); return false; } catch (error) { logger_1.logger.error(`Error checking if file has changed: ${filePath}`, { error: error instanceof Error ? error.message : String(error) }); // If there's an error, assume the file has changed to be safe logger_1.logger.incrementMetric('cacheMisses'); return true; } } /** * Update the cache entry for a file */ updateFile(filePath, timestamp, contentHash) { this.cache.set(filePath, { timestamp, contentHash }); } /** * Mark a file as processed without checking its content */ markFileProcessed(filePath) { try { const stats = fs.statSync(filePath); const currentTimestamp = stats.mtimeMs; const fileContent = fs.readFileSync(filePath, 'utf-8'); const contentHash = crypto .createHash('md5') .update(fileContent) .digest('hex'); this.updateFile(filePath, currentTimestamp, contentHash); logger_1.logger.trace(`Marked file as processed: ${filePath}`); } catch (error) { logger_1.logger.error(`Error marking file as processed: ${filePath}`, { error: error instanceof Error ? error.message : String(error) }); } } } exports.FileCache = FileCache; /** * Get or create a file cache based on the provided options */ function getFileCache(options) { const cachePath = options.incrementalCompilation && options.incrementalCachePath ? path.resolve(options.incrementalCachePath) : undefined; if (cachePath) { logger_1.logger.debug(`Creating file cache with path: ${cachePath}`); } else { logger_1.logger.debug('Creating in-memory file cache'); } return new FileCache(cachePath); } /** * Check if a file has changed since the last compilation */ function isFileUnchanged(filePath) { // This is a stub that would be replaced with the real implementation // that uses the FileCache class return false; } /** * Mark a file as processed in the cache */ function markFileAsProcessed(filePath) { // This is a stub that would be replaced with the real implementation // that uses the FileCache class } exports.FileCacheSchema = z.object({ cache: z.any(), cachePath: z.any(), initialized: z.any(), loadCache: z.any(), saveCache: z.any(), hasFileChanged: z.any(), updateFile: z.any(), markFileProcessed: z.any() });