UNPKG

@mdfriday/foundry

Version:

The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.

334 lines 12.6 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.Modules = void 0; exports.newModules = newModules; const type_1 = require("../type"); const module_1 = require("../vo/module"); const lang_1 = require("./lang"); const log_1 = require("../../../../pkg/log"); const path = __importStar(require("path")); // Create domain-specific logger for module operations const log = (0, log_1.getDomainLogger)('module', { component: 'modules' }); class Modules { constructor(info, httpClient, zipExtractor, moduleCache) { this.info = info; this.httpClient = httpClient; this.zipExtractor = zipExtractor; this.moduleCache = moduleCache; this.modules = []; this.downloadedModules = new Set(); let projectModuleDir = this.info.projDir(); // Check if this is ConfigWithModulesDir by checking if it has workspaceModuleDir method const configWithModulesDir = this.info; if (typeof configWithModulesDir.workspaceModuleDir === 'function') { projectModuleDir = configWithModulesDir.workspaceModuleDir(); } // Initialize project module with correct module directory this.projectModule = (0, module_1.newProjectModule)(this.info.osFs(), projectModuleDir, 'project-root'); // Initialize lang after all modules are set up this.lang = (0, lang_1.newLang)(this.all()); } /** * Get project module */ proj() { return this.projectModule.getModule(); } /** * Get all modules (project + downloaded) */ all() { const modules = [this.projectModule.getModule()]; modules.push(...this.modules); return modules; } /** * Check if module is the project module */ isProjMod(mod) { return mod === this.projectModule.getModule(); } /** * Load modules from import paths */ async load(onProgress) { const importPaths = this.info.importPaths(); if (importPaths.length === 0) { log.warn('No import paths configured - no modules will be downloaded'); return; } for (let i = 0; i < importPaths.length; i++) { const importPath = importPaths[i]; if (!this.downloadedModules.has(importPath)) { await this.addModule(this.projectModule.getModule(), importPath, (downloadProgress) => { onProgress?.({ modulePath: importPath, downloadPercentage: downloadProgress.percentage }); }); } } } /** * Download and add a module */ async downloadModule(moduleImport, onProgress) { try { // Check cache first const cachedMetadata = await this.moduleCache.get(moduleImport.path); if (cachedMetadata && cachedMetadata.downloadStatus === type_1.DownloadStatus.COMPLETED) { const module = await this.createModuleFromCache(moduleImport, cachedMetadata); if (await module.exists()) { return module; } } // Download module const moduleDir = this.getModuleDir(moduleImport.path); const zipPath = path.join(moduleDir, 'module.zip'); // Create metadata const metadata = { path: moduleImport.path, version: moduleImport.version || 'latest', url: moduleImport.url, dir: moduleDir, downloadStatus: type_1.DownloadStatus.DOWNLOADING, downloadedAt: new Date(), }; // Update cache with downloading status await this.moduleCache.set(moduleImport.path, metadata); try { // Download ZIP file with progress callback await this.httpClient.download(moduleImport.url, zipPath, { onProgress: (progress) => { onProgress?.({ percentage: progress.percentage }); }, }); // Extract ZIP file await this.zipExtractor.extract(zipPath, moduleDir); // Update metadata metadata.downloadStatus = type_1.DownloadStatus.COMPLETED; metadata.downloadedAt = new Date(); // Get file size try { const zipStat = await this.info.osFs().stat(zipPath); metadata.size = zipStat.size(); } catch (error) { // Ignore if we can't get size } // Clean up ZIP file try { await this.info.osFs().remove(zipPath); } catch (error) { // Ignore cleanup error } // Update cache await this.moduleCache.set(moduleImport.path, metadata); // Create module const module = (0, module_1.newModule)(this.info.osFs(), moduleDir, moduleImport.path); module.setMetadata(metadata); await module.applyMounts(moduleImport); return module; } catch (error) { // Update metadata with failed status metadata.downloadStatus = type_1.DownloadStatus.FAILED; await this.moduleCache.set(moduleImport.path, metadata); const message = error instanceof Error ? error.message : String(error); throw new type_1.ModuleError(`Failed to download module ${moduleImport.path}: ${message}`, 'DOWNLOAD_FAILED'); } } catch (error) { if (error instanceof type_1.ModuleError) { throw error; } const message = error instanceof Error ? error.message : String(error); throw new type_1.ModuleError(`Module download failed: ${message}`, 'DOWNLOAD_FAILED'); } } /** * Add a module to the collection */ async addModule(owner, importPath, onProgress) { try { // Check if already downloaded if (this.downloadedModules.has(importPath)) { return; } const moduleImport = { path: importPath, url: this.getDownloadUrl(importPath), }; // Download module with progress callback const module = await this.downloadModule(moduleImport, onProgress); // Add to collection this.modules.push(module); this.downloadedModules.add(importPath); // TODO: Support recursive imports if needed // const childImports = await this.getModuleImports(module); // for (const childImport of childImports) { // await this.addModule(module, childImport); // } } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new type_1.ModuleError(`Failed to add module ${importPath}: ${message}`, 'ADD_MODULE_FAILED'); } } /** * Create module from cached metadata */ async createModuleFromCache(moduleImport, metadata) { const module = (0, module_1.newModule)(this.info.osFs(), metadata.dir, moduleImport.path); module.setMetadata(metadata); await module.applyMounts(moduleImport); return module; } /** * Get module directory path */ getModuleDir(modulePath) { // Convert module path to safe directory name const safeName = modulePath .replace(/[/\\:*?"<>|]/g, '_') .replace(/^_+|_+$/g, ''); return path.join(this.info.moduleDir(), safeName); } /** * Get download URL for module path * This would be implemented based on your backend API */ getDownloadUrl(modulePath) { return modulePath; } /** * Get module by path */ getModuleByPath(modulePath) { return this.modules.find(m => m.path() === modulePath) || null; } /** * Check if module is downloaded */ isModuleDownloaded(modulePath) { return this.downloadedModules.has(modulePath); } /** * Get download status for module */ async getModuleStatus(modulePath) { const metadata = await this.moduleCache.get(modulePath); return metadata?.downloadStatus || type_1.DownloadStatus.PENDING; } /** * Remove module from collection */ async removeModule(modulePath) { try { // Remove from collection const index = this.modules.findIndex(m => m.path() === modulePath); if (index >= 0) { const module = this.modules[index]; // Remove directory try { await this.info.osFs().removeAll(module.dir()); } catch (error) { // Ignore if directory doesn't exist } // Remove from collection this.modules.splice(index, 1); this.downloadedModules.delete(modulePath); // Remove from cache await this.moduleCache.delete(modulePath); } } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new type_1.ModuleError(`Failed to remove module ${modulePath}: ${message}`, 'REMOVE_MODULE_FAILED'); } } /** * Clear all downloaded modules */ async clearAll() { try { // Remove all module directories for (const module of this.modules) { try { await this.info.osFs().removeAll(module.dir()); } catch (error) { // Continue removing others even if one fails } } // Clear collections this.modules = []; this.downloadedModules.clear(); // Clear cache await this.moduleCache.clear(); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new type_1.ModuleError(`Failed to clear modules: ${message}`, 'CLEAR_MODULES_FAILED'); } } /** * Get summary of all modules */ getSummary() { return { projectModule: this.projectModule.getModule().getSummary(), downloadedModules: this.modules.map(m => m.getSummary()), totalModules: this.modules.length + 1, // +1 for project module }; } /** * Get source language */ getSourceLang(source) { return this.lang.getSourceLang(source); } } exports.Modules = Modules; /** * Creates a new Modules instance */ function newModules(info, httpClient, zipExtractor, moduleCache) { return new Modules(info, httpClient, zipExtractor, moduleCache); } //# sourceMappingURL=module.js.map