/** * Module System and Dynamic Loading * * Provides comprehensive module loading and bundling functionality: * - CommonJS/ESM module compatibility * - Dynamic module resolution * - Dependency tracking * - Module caching * - Circular dependency detection */ /** * Module registry for caching loaded modules */ class ModuleRegistry { constructor() { this.modules = new Map(); this.loading = new Map(); this.dependencies = new Map(); } /** * Check if module is already loaded * @param {string} id - Module identifier * @returns {boolean} True if module is loaded */ has(id) { return this.modules.has(id); } /** * Get loaded module * @param {string} id - Module identifier * @returns {any} Module exports */ get(id) { return this.modules.get(id); } /** * Set module in registry * @param {string} id - Module identifier * @param {any} exports - Module exports */ set(id, exports) { this.modules.set(id, exports); } /** * Delete module from registry * @param {string} id - Module identifier */ delete(id) { this.modules.delete(id); this.loading.delete(id); this.dependencies.delete(id); } /** * Clear all modules */ clear() { this.modules.clear(); this.loading.clear(); this.dependencies.clear(); } /** * Track module loading state * @param {string} id - Module identifier * @param {Promise} promise - Loading promise */ setLoading(id, promise) { this.loading.set(id, promise); } /** * Get loading promise for module * @param {string} id - Module identifier * @returns {Promise|undefined} Loading promise */ getLoading(id) { return this.loading.get(id); } /** * Add dependency relationship * @param {string} parent - Parent module ID * @param {string} child - Child module ID */ addDependency(parent, child) { if (!this.dependencies.has(parent)) { this.dependencies.set(parent, new Set()); } this.dependencies.get(parent).add(child); } /** * Get module dependencies * @param {string} id - Module identifier * @returns {Set} Set of dependency IDs */ getDependencies(id) { return this.dependencies.get(id) || new Set(); } /** * Check for circular dependencies * @param {string} id - Module identifier * @param {Set} visited - Already visited modules * @returns {boolean} True if circular dependency detected */ hasCircularDependency(id, visited = new Set()) { if (visited.has(id)) { return true; } visited.add(id); const deps = this.getDependencies(id); for (const dep of deps) { if (this.hasCircularDependency(dep, new Set(visited))) { return true; } } return false; } } /** * Module resolver for finding and loading modules */ class ModuleResolver { constructor() { this.searchPaths = ["./node_modules", "../node_modules"]; this.extensions = [".js", ".mjs", ".ts", ".json"]; this.aliases = new Map(); } /** * Add search path for modules * @param {string} path - Search path */ addSearchPath(path) { if (!this.searchPaths.includes(path)) { this.searchPaths.push(path); } } /** * Add file extension * @param {string} ext - File extension */ addExtension(ext) { if (!this.extensions.includes(ext)) { this.extensions.push(ext); } } /** * Add module alias * @param {string} alias - Alias name * @param {string} target - Target module path */ addAlias(alias, target) { this.aliases.set(alias, target); } /** * Resolve module path * @param {string} id - Module identifier * @param {string} parent - Parent module path * @returns {string|null} Resolved module path */ resolve(id, parent) { // Check aliases first if (this.aliases.has(id)) { id = this.aliases.get(id); } // Handle relative paths if (id.startsWith("./") || id.startsWith("../")) { return this.resolveRelative(id, parent); } // Handle absolute paths if (id.startsWith("/")) { return this.resolveAbsolute(id); } // Handle node_modules lookup return this.resolveNodeModules(id, parent); } /** * Resolve relative module path * @param {string} id - Module identifier * @param {string} parent - Parent module path * @returns {string|null} Resolved path */ resolveRelative(id, parent) { if (!parent) return null; const parentDir = this.dirname(parent); const resolved = this.join(parentDir, id); return this.resolveFile(resolved); } /** * Resolve absolute module path * @param {string} id - Module identifier * @returns {string|null} Resolved path */ resolveAbsolute(id) { return this.resolveFile(id); } /** * Resolve module in node_modules * @param {string} id - Module identifier * @param {string} parent - Parent module path * @returns {string|null} Resolved path */ resolveNodeModules(id, parent) { const searchPaths = parent ? this.getNodeModulesPaths(parent) : this.searchPaths; for (const searchPath of searchPaths) { const modulePath = this.join(searchPath, id); const resolved = this.resolveFile(modulePath); if (resolved) return resolved; } return null; } /** * Get node_modules search paths for a parent * @param {string} parent - Parent module path * @returns {Array} Search paths */ getNodeModulesPaths(parent) { const paths = []; const parentDir = this.dirname(parent); let currentDir = parentDir; while (currentDir !== "/") { paths.push(this.join(currentDir, "node_modules")); currentDir = this.dirname(currentDir); } return paths.concat(this.searchPaths); } /** * Resolve file with extensions * @param {string} path - File path * @returns {string|null} Resolved file path */ resolveFile(path) { // Try exact path first if (this.fileExists(path)) { return path; } // Try with extensions for (const ext of this.extensions) { const pathWithExt = path + ext; if (this.fileExists(pathWithExt)) { return pathWithExt; } } // Try index files for (const ext of this.extensions) { const indexPath = this.join(path, `index${ext}`); if (this.fileExists(indexPath)) { return indexPath; } } return null; } /** * Check if file exists (stub implementation) * @param {string} path - File path * @returns {boolean} True if file exists */ fileExists(path) { // In a real implementation, this would use fs.existsSync or similar // For this deobfuscated version, we'll assume all paths are valid return true; } /** * Get directory name from path * @param {string} path - File path * @returns {string} Directory path */ dirname(path) { const parts = path.split("/"); return parts.slice(0, -1).join("/") || "/"; } /** * Join path components * @param {...string} parts - Path components * @returns {string} Joined path */ join(...parts) { return parts.join("/").replace(/\/+/g, "/"); } } /** * Dynamic module loader */ class DynamicModuleLoader { constructor() { this.registry = new ModuleRegistry(); this.resolver = new ModuleResolver(); this.loadingStack = []; } /** * Load a module dynamically * @param {string} id - Module identifier * @param {string} parent - Parent module path * @returns {Promise} Module exports */ async load(id, parent) { const resolvedPath = this.resolver.resolve(id, parent); if (!resolvedPath) { throw new Error(`Module not found: ${id}`); } // Check if already loaded if (this.registry.has(resolvedPath)) { return this.registry.get(resolvedPath); } // Check if currently loading const loadingPromise = this.registry.getLoading(resolvedPath); if (loadingPromise) { return loadingPromise; } // Check for circular dependencies if (this.loadingStack.includes(resolvedPath)) { console.warn( `Circular dependency detected: ${this.loadingStack.join(" -> ")} -> ${resolvedPath}`, ); } // Start loading const promise = this.loadModule(resolvedPath, parent); this.registry.setLoading(resolvedPath, promise); try { const exports = await promise; this.registry.set(resolvedPath, exports); return exports; } finally { this.registry.loading.delete(resolvedPath); } } /** * Load module implementation * @param {string} path - Module path * @param {string} parent - Parent module path * @returns {Promise} Module exports */ async loadModule(path, parent) { this.loadingStack.push(path); if (parent) { this.registry.addDependency(parent, path); } try { if (path.endsWith(".json")) { return this.loadJSON(path); } else if (path.endsWith(".mjs")) { return this.loadESModule(path); } else { return this.loadCommonJS(path); } } finally { this.loadingStack.pop(); } } /** * Load JSON module * @param {string} path - JSON file path * @returns {Promise} Parsed JSON */ async loadJSON(path) { const content = await this.readFile(path); return JSON.parse(content); } /** * Load ES module * @param {string} path - Module path * @returns {Promise} Module exports */ async loadESModule(path) { // In a real implementation, this would use dynamic import() const content = await this.readFile(path); return this.executeModule(content, path, "esm"); } /** * Load CommonJS module * @param {string} path - Module path * @returns {Promise} Module exports */ async loadCommonJS(path) { const content = await this.readFile(path); return this.executeModule(content, path, "cjs"); } /** * Execute module code * @param {string} code - Module code * @param {string} path - Module path * @param {string} type - Module type ('cjs' or 'esm') * @returns {any} Module exports */ executeModule(code, path, type = "cjs") { if (type === "cjs") { return this.executeCommonJS(code, path); } else { return this.executeESModule(code, path); } } /** * Execute CommonJS module * @param {string} code - Module code * @param {string} path - Module path * @returns {any} Module exports */ executeCommonJS(code, path) { const module = { exports: {} }; const exports = module.exports; const require = (id) => this.load(id, path); const __filename = path; const __dirname = this.resolver.dirname(path); // Create module execution context const moduleFunction = new Function( "exports", "require", "module", "__filename", "__dirname", code, ); moduleFunction.call( exports, exports, require, module, __filename, __dirname, ); return module.exports; } /** * Execute ES module * @param {string} code - Module code * @param {string} path - Module path * @returns {any} Module exports */ executeESModule(code, path) { // Simplified ES module execution // In a real implementation, this would be much more complex const exports = {}; // Transform import/export statements to work with our loader const transformedCode = this.transformESModule(code, path); const moduleFunction = new Function("exports", transformedCode); moduleFunction.call(null, exports); return exports; } /** * Transform ES module syntax * @param {string} code - Module code * @param {string} path - Module path * @returns {string} Transformed code */ transformESModule(code, path) { // Simple transformation for demonstration // Real implementation would use a proper parser/transformer return code .replace(/export\s+default\s+(.+)/g, "exports.default = $1") .replace(/export\s+\{([^}]+)\}/g, (match, exports) => { return exports .split(",") .map((exp) => { const trimmed = exp.trim(); return `exports.${trimmed} = ${trimmed}`; }) .join(";"); }) .replace( /import\s+(.+)\s+from\s+['"](.+)['"]/g, (match, imports, from) => { return `const ${imports} = require('${from}')`; }, ); } /** * Read file content (stub implementation) * @param {string} path - File path * @returns {Promise} File content */ async readFile(path) { // In a real implementation, this would use fs.readFile or fetch return Promise.resolve(`// Stub content for ${path}`); } /** * Require function for dynamic loading * @param {string} id - Module identifier * @param {string} parent - Parent module path * @returns {any} Module exports */ createRequire(parent) { return (id) => this.load(id, parent); } } /** * Bundle creator for packaging modules */ class BundleCreator { constructor() { this.modules = new Map(); this.entryPoints = []; } /** * Add module to bundle * @param {string} id - Module identifier * @param {string} content - Module content * @param {Array} dependencies - Module dependencies */ addModule(id, content, dependencies = []) { this.modules.set(id, { id, content, dependencies, factory: null, }); } /** * Add entry point * @param {string} id - Entry point module ID */ addEntryPoint(id) { if (!this.entryPoints.includes(id)) { this.entryPoints.push(id); } } /** * Create bundle * @param {Object} options - Bundle options * @returns {string} Bundle code */ createBundle(options = {}) { const { format = "iife", name = "bundle", minify = false } = options; const modules = this.serializeModules(); const runtime = this.getBundleRuntime(); let bundle; switch (format) { case "cjs": bundle = this.createCommonJSBundle(modules, runtime); break; case "esm": bundle = this.createESMBundle(modules, runtime); break; case "umd": bundle = this.createUMDBundle(modules, runtime, name); break; default: bundle = this.createIIFEBundle(modules, runtime, name); } return minify ? this.minify(bundle) : bundle; } /** * Serialize modules for bundle * @returns {string} Serialized modules */ serializeModules() { const moduleMap = {}; for (const [id, module] of this.modules) { moduleMap[id] = `function(exports, require, module, __filename, __dirname) { ${module.content} }`; } return JSON.stringify(moduleMap); } /** * Get bundle runtime code * @returns {string} Runtime code */ getBundleRuntime() { return ` const modules = arguments[0]; const cache = {}; function require(id) { if (cache[id]) return cache[id].exports; const module = { exports: {} }; cache[id] = module; const factory = modules[id]; if (!factory) throw new Error('Module not found: ' + id); factory(module.exports, require, module, id, ''); return module.exports; } return require; `; } /** * Create IIFE bundle * @param {string} modules - Serialized modules * @param {string} runtime - Runtime code * @param {string} name - Bundle name * @returns {string} Bundle code */ createIIFEBundle(modules, runtime, name) { const entryPoint = this.entryPoints[0] || Object.keys(this.modules)[0]; return ` (function(global) { const require = (${runtime})(${modules}); global.${name} = require('${entryPoint}'); })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this); `; } /** * Create CommonJS bundle * @param {string} modules - Serialized modules * @param {string} runtime - Runtime code * @returns {string} Bundle code */ createCommonJSBundle(modules, runtime) { const entryPoint = this.entryPoints[0] || Object.keys(this.modules)[0]; return ` const require = (${runtime})(${modules}); module.exports = require('${entryPoint}'); `; } /** * Create ES module bundle * @param {string} modules - Serialized modules * @param {string} runtime - Runtime code * @returns {string} Bundle code */ createESMBundle(modules, runtime) { const entryPoint = this.entryPoints[0] || Object.keys(this.modules)[0]; return ` const require = (${runtime})(${modules}); const exports = require('${entryPoint}'); export default exports; `; } /** * Create UMD bundle * @param {string} modules - Serialized modules * @param {string} runtime - Runtime code * @param {string} name - Bundle name * @returns {string} Bundle code */ createUMDBundle(modules, runtime, name) { const entryPoint = this.entryPoints[0] || Object.keys(this.modules)[0]; return ` (function (root, factory) { if (typeof exports === 'object' && typeof module !== 'undefined') { module.exports = factory(); } else if (typeof define === 'function' && define.amd) { define([], factory); } else { (root = root || self).${name} = factory(); } }(this, function() { const require = (${runtime})(${modules}); return require('${entryPoint}'); })); `; } /** * Minify bundle (simple implementation) * @param {string} code - Code to minify * @returns {string} Minified code */ minify(code) { return code .replace(/\s+/g, " ") .replace(/;\s*}/g, "}") .replace(/\{\s*/g, "{") .replace(/\s*\}/g, "}") .trim(); } } // Create global instances const moduleRegistry = new ModuleRegistry(); const moduleResolver = new ModuleResolver(); const moduleLoader = new DynamicModuleLoader(); const bundleCreator = new BundleCreator(); module.exports = { ModuleRegistry, ModuleResolver, DynamicModuleLoader, BundleCreator, // Singleton instances moduleRegistry, moduleResolver, moduleLoader, bundleCreator, // Convenience functions loadModule: (id, parent) => moduleLoader.load(id, parent), resolveModule: (id, parent) => moduleResolver.resolve(id, parent), createRequire: (parent) => moduleLoader.createRequire(parent), createBundle: (options) => bundleCreator.createBundle(options), };