"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.patchCreateProgram = exports.addDiagnosticFactory = exports.transformerErrors = void 0;
var path_1 = require("path");
var PluginCreator_1 = require("./PluginCreator");
exports.transformerErrors = new WeakMap();
function addDiagnosticFactory(program) {
    return function (diag) {
        var arr = exports.transformerErrors.get(program) || [];
        arr.push(diag);
        exports.transformerErrors.set(program, arr);
    };
}
exports.addDiagnosticFactory = addDiagnosticFactory;
function patchCreateProgram(tsm, forceReadConfig, projectDir) {
    if (forceReadConfig === void 0) { forceReadConfig = false; }
    if (projectDir === void 0) { projectDir = process.cwd(); }
    var originCreateProgram = tsm.createProgram;
    function createProgram(rootNamesOrOptions, options, host, oldProgram, configFileParsingDiagnostics) {
        var rootNames;
        var createOpts;
        if (!Array.isArray(rootNamesOrOptions)) {
            createOpts = rootNamesOrOptions;
        }
        if (createOpts) {
            rootNames = createOpts.rootNames;
            options = createOpts.options;
            host = createOpts.host;
            oldProgram = createOpts.oldProgram;
            configFileParsingDiagnostics = createOpts.configFileParsingDiagnostics;
        }
        else {
            options = options;
            rootNames = rootNamesOrOptions;
        }
        if (forceReadConfig) {
            var info = getConfig(tsm, options, rootNames, projectDir);
            options = info.compilerOptions;
            if (createOpts) {
                createOpts.options = options;
            }
            projectDir = info.projectDir;
        }
        var program = createOpts
            ? originCreateProgram(createOpts)
            : originCreateProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics);
        var plugins = preparePluginsFromCompilerOptions(options.plugins);
        var pluginCreator = new PluginCreator_1.PluginCreator(tsm, plugins, projectDir);
        var originEmit = program.emit;
        /**
         * The emit method has the following declaration:
         * https://github.com/microsoft/TypeScript/blob/bfc55b5762443c37ecdef08a3b5a4e057b4d1e85/src/compiler/builderPublic.ts#L101
         * The declaration specifies 5 arguments, but it's not true. Sometimes the emit method takes 6 arguments.
         */
        program.emit = function newEmit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers, arg) {
            var mergedTransformers = pluginCreator.createTransformers({ program: program }, customTransformers);
            var result = originEmit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, mergedTransformers, arg);
            // todo: doesn't work with 3.7
            // result.diagnostics = [...result.diagnostics, ...transformerErrors.get(program)!];
            return result;
        };
        return program;
    }
    tsm.createProgram = createProgram;
    return tsm;
}
exports.patchCreateProgram = patchCreateProgram;
function getConfig(tsm, compilerOptions, rootFileNames, defaultDir) {
    if (compilerOptions.configFilePath === undefined) {
        var dir = rootFileNames.length > 0 ? (0, path_1.dirname)(rootFileNames[0]) : defaultDir;
        var tsconfigPath = tsm.findConfigFile(dir, tsm.sys.fileExists);
        if (tsconfigPath) {
            var projectDir = (0, path_1.dirname)(tsconfigPath);
            var config = readConfig(tsm, tsconfigPath, (0, path_1.dirname)(tsconfigPath));
            compilerOptions = __assign(__assign({}, config.options), compilerOptions);
            return {
                projectDir: projectDir,
                compilerOptions: compilerOptions,
            };
        }
    }
    return {
        projectDir: (0, path_1.dirname)(compilerOptions.configFilePath),
        compilerOptions: compilerOptions,
    };
}
function readConfig(tsm, configFileNamePath, projectDir) {
    var result = tsm.readConfigFile(configFileNamePath, tsm.sys.readFile);
    if (result.error) {
        throw new Error('tsconfig.json error: ' + result.error.messageText);
    }
    return tsm.parseJsonConfigFileContent(result.config, tsm.sys, projectDir, undefined, configFileNamePath);
}
function preparePluginsFromCompilerOptions(plugins) {
    if (!plugins)
        return [];
    // old transformers system
    if (plugins.length === 1 && plugins[0].customTransformers) {
        var _a = plugins[0].customTransformers, _b = _a.before, before = _b === void 0 ? [] : _b, _c = _a.after, after = _c === void 0 ? [] : _c;
        return __spreadArray(__spreadArray([], before.map(function (item) { return ({ transform: item }); }), true), after.map(function (item) { return ({ transform: item, after: true }); }), true);
    }
    return plugins;
}
