"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;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModuleResolver = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
class ModuleResolver {
    constructor(options = {}) {
        this.options = {
            baseUrl: options.baseUrl || process.cwd(),
            paths: options.paths || {},
            extensions: options.extensions || ['.som', '.js', '.json'],
            moduleDirectories: options.moduleDirectories || ['node_modules'],
            allowJs: options.allowJs ?? true,
            resolveJsonModule: options.resolveJsonModule ?? true,
        };
    }
    /**
     * Resolve a module specifier to an absolute file path
     */
    resolve(specifier, fromFile) {
        // Determine a correct base directory whether 'fromFile' is a file path or a directory path
        let fromDir;
        try {
            if (fs.existsSync(fromFile) && fs.statSync(fromFile).isDirectory()) {
                fromDir = fromFile;
            }
            else {
                fromDir = path.dirname(fromFile);
            }
        }
        catch {
            // Fallback: treat input as a file path
            fromDir = path.dirname(fromFile);
        }
        // Handle already absolute file paths
        if (path.isAbsolute(specifier) && fs.existsSync(specifier)) {
            return {
                resolvedPath: specifier,
                isExternalLibrary: false,
                extension: path.extname(specifier),
            };
        }
        // Handle relative imports (./module, ../module)
        if (specifier.startsWith('./') || specifier.startsWith('../')) {
            return this.resolveRelative(specifier, fromDir);
        }
        // Handle absolute imports (/module)
        if (specifier.startsWith('/')) {
            return this.resolveAbsolute(specifier);
        }
        // Handle path mapping
        const mappedPath = this.resolveMappedPath(specifier);
        if (mappedPath) {
            return mappedPath;
        }
        // Handle node_modules resolution
        return this.resolveNodeModules(specifier, fromDir);
    }
    resolveRelative(specifier, fromDir) {
        const targetPath = path.resolve(fromDir, specifier);
        return this.resolveFile(targetPath, false);
    }
    resolveAbsolute(specifier) {
        const targetPath = path.resolve(this.options.baseUrl, specifier.slice(1));
        return this.resolveFile(targetPath, false);
    }
    resolveMappedPath(specifier) {
        for (const [pattern, mappings] of Object.entries(this.options.paths)) {
            if (this.matchesPattern(specifier, pattern)) {
                for (const mapping of mappings) {
                    const mappedSpecifier = this.applyMapping(specifier, pattern, mapping);
                    const targetPath = path.resolve(this.options.baseUrl, mappedSpecifier);
                    try {
                        return this.resolveFile(targetPath, false);
                    }
                    catch {
                        continue; // Try next mapping
                    }
                }
            }
        }
        return null;
    }
    resolveNodeModules(specifier, fromDir) {
        let currentDir = fromDir;
        while (currentDir !== path.dirname(currentDir)) {
            for (const moduleDir of this.options.moduleDirectories) {
                const modulePath = path.join(currentDir, moduleDir, specifier);
                try {
                    return this.resolveFile(modulePath, true, specifier);
                }
                catch {
                    // Continue searching
                }
            }
            currentDir = path.dirname(currentDir);
        }
        throw new Error(`Module not found: ${specifier}`);
    }
    resolveFile(targetPath, isExternal, packageName) {
        // Try exact path first
        if (fs.existsSync(targetPath) && fs.statSync(targetPath).isFile()) {
            return {
                resolvedPath: targetPath,
                isExternalLibrary: isExternal,
                packageName,
                extension: path.extname(targetPath),
            };
        }
        // Try with extensions
        for (const ext of this.options.extensions) {
            const pathWithExt = targetPath + ext;
            if (fs.existsSync(pathWithExt) && fs.statSync(pathWithExt).isFile()) {
                return {
                    resolvedPath: pathWithExt,
                    isExternalLibrary: isExternal,
                    packageName,
                    extension: ext,
                };
            }
        }
        // Try as directory with index file
        if (fs.existsSync(targetPath) && fs.statSync(targetPath).isDirectory()) {
            // Check for package.json
            const packageJsonPath = path.join(targetPath, 'package.json');
            if (fs.existsSync(packageJsonPath)) {
                const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
                if (packageJson.main) {
                    const mainPath = path.resolve(targetPath, packageJson.main);
                    return this.resolveFile(mainPath, isExternal, packageName);
                }
            }
            // Try index files
            for (const ext of this.options.extensions) {
                const indexPath = path.join(targetPath, `index${ext}`);
                if (fs.existsSync(indexPath) && fs.statSync(indexPath).isFile()) {
                    return {
                        resolvedPath: indexPath,
                        isExternalLibrary: isExternal,
                        packageName,
                        extension: ext,
                    };
                }
            }
        }
        throw new Error(`Cannot resolve module: ${targetPath}`);
    }
    matchesPattern(specifier, pattern) {
        if (pattern === '*')
            return true;
        if (pattern.endsWith('/*')) {
            const prefix = pattern.slice(0, -2);
            return specifier.startsWith(prefix);
        }
        return specifier === pattern;
    }
    applyMapping(specifier, pattern, mapping) {
        if (pattern === '*') {
            return mapping.replace('*', specifier);
        }
        if (pattern.endsWith('/*')) {
            const prefix = pattern.slice(0, -2);
            const suffix = specifier.slice(prefix.length);
            return mapping.replace('*', suffix);
        }
        return mapping;
    }
    /**
     * Get all possible file extensions for module resolution
     */
    getExtensions() {
        return [...this.options.extensions];
    }
    /**
     * Check if a file extension is supported
     */
    isSupported(extension) {
        return this.options.extensions.includes(extension);
    }
    /**
     * Update resolver options
     */
    updateOptions(options) {
        this.options = { ...this.options, ...options };
    }
}
exports.ModuleResolver = ModuleResolver;
//# sourceMappingURL=module-resolver.js.map