"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.loadConfig = exports.ConfigError = void 0;
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
class ConfigError extends Error {
    constructor(message, details = []) {
        super(message);
        this.name = 'ConfigError';
        this.details = details;
    }
}
exports.ConfigError = ConfigError;
function isObject(value) {
    return typeof value === 'object' && value !== null;
}
function validateCompilerOptions(options, path = 'compilerOptions') {
    const errors = [];
    if (!isObject(options)) {
        return [{ path, message: 'must be an object' }];
    }
    // Validate target
    if (options.target !== undefined) {
        const validTargets = ['es5', 'es2015', 'es2020', 'esnext'];
        if (typeof options.target !== 'string' || !validTargets.includes(options.target)) {
            errors.push({
                path: `${path}.target`,
                message: `must be one of: ${validTargets.join(', ')}`,
            });
        }
    }
    // Validate boolean options
    const booleanOptions = ['sourceMap', 'minify', 'noTypeCheck', 'strict', 'watch', 'compileOnSave'];
    for (const option of booleanOptions) {
        if (options[option] !== undefined && typeof options[option] !== 'boolean') {
            errors.push({
                path: `${path}.${option}`,
                message: 'must be a boolean',
            });
        }
    }
    // Validate string options
    const stringOptions = ['output', 'outDir'];
    for (const option of stringOptions) {
        if (options[option] !== undefined && typeof options[option] !== 'string') {
            errors.push({
                path: `${path}.${option}`,
                message: 'must be a string',
            });
        }
    }
    // Check for unknown properties in compilerOptions
    const knownOptions = [
        'output',
        'target',
        'sourceMap',
        'minify',
        'noTypeCheck',
        'strict',
        'outDir',
        'watch',
        'compileOnSave',
    ];
    for (const key of Object.keys(options)) {
        if (!knownOptions.includes(key)) {
            errors.push({
                path: `${path}.${key}`,
                message: `unknown compiler option. Known options: ${knownOptions.join(', ')}`,
            });
        }
    }
    return errors;
}
function validateModuleSystem(config, basePath = 'moduleSystem') {
    const errors = [];
    if (config === undefined)
        return errors;
    if (!isObject(config)) {
        return [{ path: basePath, message: 'must be an object' }];
    }
    // Validate top-level properties
    errors.push(...validateModuleSystemTopLevel(config, basePath));
    const moduleConfig = config;
    // Validate each section
    errors.push(...validateResolutionSection(moduleConfig.resolution, `${basePath}.resolution`));
    errors.push(...validateLoadingSection(moduleConfig.loading, `${basePath}.loading`));
    // Reuse compiler options validation for optional compilation section
    if (moduleConfig.compilation !== undefined) {
        errors.push(...validateCompilerOptions(moduleConfig.compilation, `${basePath}.compilation`));
    }
    return errors;
}
function validateModuleSystemTopLevel(config, basePath) {
    const errors = [];
    const knownTop = [
        'resolution',
        'loading',
        'compilation',
        'metrics',
        'circuitBreakers',
        'logger',
        'managementServer',
        'managementPort',
    ];
    for (const key of Object.keys(config)) {
        if (!knownTop.includes(key)) {
            errors.push({ path: `${basePath}.${key}`, message: `unknown property` });
        }
    }
    return errors;
}
function validateResolutionSection(resolution, basePath) {
    const errors = [];
    if (resolution === undefined)
        return errors;
    if (typeof resolution !== 'object' || resolution === null) {
        return [{ path: basePath, message: 'must be an object' }];
    }
    const res = resolution;
    // Validate individual properties
    errors.push(...validateResolutionBaseUrl(res.baseUrl, basePath));
    errors.push(...validateResolutionPaths(res.paths, basePath));
    errors.push(...validateResolutionExtensions(res.extensions, basePath));
    errors.push(...validateResolutionModuleDirectories(res.moduleDirectories, basePath));
    errors.push(...validateResolutionBooleanFlags(res, basePath));
    return errors;
}
function validateResolutionBaseUrl(baseUrl, basePath) {
    if (baseUrl !== undefined && typeof baseUrl !== 'string') {
        return [{ path: `${basePath}.baseUrl`, message: 'must be a string' }];
    }
    return [];
}
function validateResolutionPaths(paths, basePath) {
    if (paths === undefined)
        return [];
    if (typeof paths !== 'object' || paths === null) {
        return [{ path: `${basePath}.paths`, message: 'must be an object' }];
    }
    for (const [k, v] of Object.entries(paths)) {
        if (typeof k !== 'string' || !Array.isArray(v) || v.some(x => typeof x !== 'string')) {
            return [{ path: `${basePath}.paths`, message: 'must be Record<string,string[]>' }];
        }
    }
    return [];
}
function validateResolutionExtensions(extensions, basePath) {
    const stringArray = (arr) => Array.isArray(arr) && arr.every(x => typeof x === 'string');
    if (extensions !== undefined && !stringArray(extensions)) {
        return [{ path: `${basePath}.extensions`, message: 'must be string[]' }];
    }
    return [];
}
function validateResolutionModuleDirectories(moduleDirectories, basePath) {
    const stringArray = (arr) => Array.isArray(arr) && arr.every(x => typeof x === 'string');
    if (moduleDirectories !== undefined && !stringArray(moduleDirectories)) {
        return [{ path: `${basePath}.moduleDirectories`, message: 'must be string[]' }];
    }
    return [];
}
function validateResolutionBooleanFlags(res, basePath) {
    const errors = [];
    if (res.allowJs !== undefined && typeof res.allowJs !== 'boolean') {
        errors.push({ path: `${basePath}.allowJs`, message: 'must be a boolean' });
    }
    if (res.resolveJsonModule !== undefined && typeof res.resolveJsonModule !== 'boolean') {
        errors.push({ path: `${basePath}.resolveJsonModule`, message: 'must be a boolean' });
    }
    return errors;
}
function validateLoadingSection(loading, basePath) {
    const errors = [];
    if (loading === undefined)
        return errors;
    if (typeof loading !== 'object' || loading === null) {
        return [{ path: basePath, message: 'must be an object' }];
    }
    const load = loading;
    if (load.encoding !== undefined && typeof load.encoding !== 'string') {
        errors.push({ path: `${basePath}.encoding`, message: 'must be a string' });
    }
    if (load.cache !== undefined && typeof load.cache !== 'boolean') {
        errors.push({ path: `${basePath}.cache`, message: 'must be a boolean' });
    }
    if (load.circularDependencyStrategy !== undefined &&
        !['error', 'warn', 'ignore'].includes(load.circularDependencyStrategy)) {
        errors.push({
            path: `${basePath}.circularDependencyStrategy`,
            message: `must be one of: error, warn, ignore`,
        });
    }
    return errors;
}
function validateBundle(config, basePath = 'bundle') {
    const errors = [];
    if (config === undefined)
        return errors;
    if (!isObject(config)) {
        return [{ path: basePath, message: 'must be an object' }];
    }
    const obj = config;
    // Validate each property separately to reduce complexity
    errors.push(...validateBundleFormat(obj.format, basePath));
    errors.push(...validateBundleBooleanProps(obj, basePath));
    errors.push(...validateBundleOutput(obj.output, basePath));
    errors.push(...validateBundleExternals(obj.externals, basePath));
    return errors;
}
function validateBundleFormat(format, basePath) {
    if (format !== undefined && format !== 'commonjs') {
        return [
            {
                path: `${basePath}.format`,
                message: "SomonScript currently supports only the 'commonjs' bundle format",
            },
        ];
    }
    return [];
}
function validateBundleBooleanProps(obj, basePath) {
    const errors = [];
    if (obj.minify !== undefined && typeof obj.minify !== 'boolean') {
        errors.push({ path: `${basePath}.minify`, message: 'must be a boolean' });
    }
    if (obj.sourceMaps !== undefined && typeof obj.sourceMaps !== 'boolean') {
        errors.push({ path: `${basePath}.sourceMaps`, message: 'must be a boolean' });
    }
    if (obj.inlineSources !== undefined && typeof obj.inlineSources !== 'boolean') {
        errors.push({ path: `${basePath}.inlineSources`, message: 'must be a boolean' });
    }
    return errors;
}
function validateBundleOutput(output, basePath) {
    if (output !== undefined && typeof output !== 'string') {
        return [{ path: `${basePath}.output`, message: 'must be a string' }];
    }
    return [];
}
function validateBundleExternals(externals, basePath) {
    if (externals !== undefined) {
        if (!Array.isArray(externals) || externals.some(x => typeof x !== 'string')) {
            return [{ path: `${basePath}.externals`, message: 'must be string[]' }];
        }
    }
    return [];
}
function validateConfig(config) {
    const errors = [];
    if (!isObject(config)) {
        return [{ path: 'root', message: 'configuration must be an object' }];
    }
    // Check for unknown top-level properties
    const knownProperties = ['compilerOptions', 'moduleSystem', 'bundle'];
    for (const key of Object.keys(config)) {
        if (!knownProperties.includes(key)) {
            errors.push({
                path: key,
                message: `unknown configuration property. Known properties: ${knownProperties.join(', ')}`,
            });
        }
    }
    // Validate compilerOptions if present
    if (config.compilerOptions !== undefined) {
        errors.push(...validateCompilerOptions(config.compilerOptions));
    }
    // Validate moduleSystem if present
    if (config.moduleSystem !== undefined) {
        errors.push(...validateModuleSystem(config.moduleSystem));
    }
    // Validate bundle if present
    if (config.bundle !== undefined) {
        errors.push(...validateBundle(config.bundle));
    }
    return errors;
}
function loadConfigFromFile(configPath) {
    let fileContents;
    try {
        fileContents = fs.readFileSync(configPath, 'utf-8');
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : String(error);
        throw new ConfigError(`Failed to read config file ${configPath}: ${reason}`);
    }
    let parsed;
    try {
        parsed = JSON.parse(fileContents);
    }
    catch (error) {
        const reason = error instanceof Error ? error.message : String(error);
        throw new ConfigError(`Failed to parse config file ${configPath}: ${reason}`);
    }
    const validationErrors = validateConfig(parsed);
    if (validationErrors.length > 0) {
        throw new ConfigError(`Invalid configuration in ${configPath}`, validationErrors);
    }
    return parsed;
}
function loadConfig(startPath) {
    let dir = path.resolve(startPath);
    let parent = '';
    while (dir !== parent) {
        const configPath = path.join(dir, 'somon.config.json');
        if (fs.existsSync(configPath)) {
            return loadConfigFromFile(configPath);
        }
        parent = dir;
        dir = path.dirname(dir);
    }
    return {};
}
exports.loadConfig = loadConfig;
//# sourceMappingURL=config.js.map