"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.safeCall = exports.ruleWorker = exports.languageFeatureWorker = exports.documentFeatureWorker = void 0;
const definePlugin_1 = require("./definePlugin");
async function documentFeatureWorker(context, uri, isValidSourceMap, worker, transform, combineResult) {
    return languageFeatureWorker(context, uri, undefined, (_, map, file) => {
        if (isValidSourceMap(file, map)) {
            return [undefined];
        }
        return [];
    }, worker, transform, combineResult);
}
exports.documentFeatureWorker = documentFeatureWorker;
async function languageFeatureWorker(context, uri, arg, transformArg, worker, transform, combineResult, reportProgress) {
    const document = context.getTextDocument(uri);
    const virtualFile = context.documents.getSourceByUri(uri)?.root;
    let results = [];
    if (virtualFile) {
        await (0, definePlugin_1.visitEmbedded)(context.documents, virtualFile, async (file, map) => {
            for (const mappedArg of transformArg(arg, map, file)) {
                for (const [pluginId, plugin] of Object.entries(context.plugins)) {
                    const embeddedResult = await safeCall(() => worker(plugin, map.virtualFileDocument, mappedArg, map, file), 'plugin ' + pluginId + ' crashed on ' + map.virtualFileDocument.uri);
                    if (!embeddedResult)
                        continue;
                    const result = transform(embeddedResult, map);
                    if (!result)
                        continue;
                    results.push(result);
                    if (!combineResult)
                        return false;
                    const isEmptyArray = Array.isArray(result) && result.length === 0;
                    if (reportProgress && !isEmptyArray) {
                        reportProgress(combineResult(results));
                    }
                }
            }
            return true;
        });
    }
    else if (document) {
        for (const [pluginId, plugin] of Object.entries(context.plugins)) {
            const embeddedResult = await safeCall(() => worker(plugin, document, arg, undefined, undefined), 'plugin ' + pluginId + ' crashed on ' + uri);
            if (!embeddedResult)
                continue;
            const result = transform(embeddedResult, undefined);
            if (!result)
                continue;
            results.push(result);
            if (!combineResult)
                break;
            const isEmptyArray = Array.isArray(result) && result.length === 0;
            if (reportProgress && !isEmptyArray) {
                reportProgress(combineResult(results));
            }
        }
    }
    if (combineResult && results.length > 0) {
        return combineResult(results);
    }
    else if (results.length > 0) {
        return results[0];
    }
}
exports.languageFeatureWorker = languageFeatureWorker;
async function ruleWorker(context, api, uri, isValidSourceMap, worker, transform, combineResult, reportProgress) {
    const document = context.getTextDocument(uri);
    const virtualFile = context.documents.getSourceByUri(uri)?.root;
    let results = [];
    if (virtualFile) {
        await (0, definePlugin_1.visitEmbedded)(context.documents, virtualFile, async (file, map) => {
            if (!isValidSourceMap(file)) {
                return true;
            }
            let ruleCtx = {
                // project context
                modules: { typescript: context.typescript?.module },
                uriToFileName: context.uriToFileName,
                fileNameToUri: context.fileNameToUri,
                rootUri: context.rootUri,
                locale: context.locale,
                getConfiguration: context.configurationHost?.getConfiguration,
                onDidChangeConfiguration: context.configurationHost?.onDidChangeConfiguration,
                settings: context.config.lint?.settings ?? {},
                // document context
                ruleId: '',
                document: map.virtualFileDocument,
                report: () => { },
            };
            for (const plugin of Object.values(context.plugins)) {
                try {
                    if (plugin.resolveRuleContext) {
                        ruleCtx = await plugin.resolveRuleContext(ruleCtx, api === 'onFormat' ? 'format' : api === 'onSyntax' ? 'syntax' : 'semantic');
                    }
                }
                catch (err) {
                    console.warn('plugin rule context setup crashed on ' + map.virtualFileDocument.uri + ': ' + err);
                }
            }
            for (const ruleName in context.config.lint?.rules) {
                const rule = context.config.lint?.rules[ruleName];
                if (!rule) {
                    continue;
                }
                ruleCtx.ruleId = ruleName;
                const embeddedResult = await safeCall(() => worker(ruleName, rule, ruleCtx), 'rule ' + ruleName + ' crashed on ' + map.virtualFileDocument.uri);
                if (!embeddedResult)
                    continue;
                const result = transform(embeddedResult, map);
                if (!result)
                    continue;
                results.push(result);
                if (!combineResult)
                    return false;
                const isEmptyArray = Array.isArray(result) && result.length === 0;
                if (reportProgress && !isEmptyArray) {
                    reportProgress(combineResult(results));
                }
            }
            return true;
        });
    }
    else if (document) {
        let ruleCtx = {
            // project context
            modules: { typescript: context.typescript?.module },
            uriToFileName: context.uriToFileName,
            fileNameToUri: context.fileNameToUri,
            rootUri: context.rootUri,
            locale: context.locale,
            getConfiguration: context.configurationHost?.getConfiguration,
            onDidChangeConfiguration: context.configurationHost?.onDidChangeConfiguration,
            settings: context.config.lint?.settings ?? {},
            // document context
            ruleId: '',
            document,
            report: () => { },
        };
        for (const plugin of Object.values(context.plugins)) {
            try {
                if (plugin.resolveRuleContext) {
                    ruleCtx = await plugin.resolveRuleContext(ruleCtx, api === 'onFormat' ? 'format' : api === 'onSyntax' ? 'syntax' : 'semantic');
                }
            }
            catch (err) {
                console.warn('plugin rule context setup crashed on ' + document.uri + ': ' + err);
            }
        }
        for (const ruleName in context.config.lint?.rules) {
            const rule = context.config.lint?.rules[ruleName];
            if (!rule) {
                continue;
            }
            ruleCtx.ruleId = ruleName;
            const embeddedResult = await safeCall(() => worker(ruleName, rule, ruleCtx), 'rule ' + ruleName + ' crashed on ' + document.uri);
            if (!embeddedResult)
                continue;
            const result = transform(embeddedResult, undefined);
            if (!result)
                continue;
            results.push(result);
            if (!combineResult)
                break;
            const isEmptyArray = Array.isArray(result) && result.length === 0;
            if (reportProgress && !isEmptyArray) {
                reportProgress(combineResult(results));
            }
        }
    }
    if (combineResult && results.length > 0) {
        return combineResult(results);
    }
    else if (results.length > 0) {
        return results[0];
    }
}
exports.ruleWorker = ruleWorker;
async function safeCall(cb, errorMsg) {
    try {
        return await cb();
    }
    catch (err) {
        console.warn(errorMsg, err);
    }
}
exports.safeCall = safeCall;
//# sourceMappingURL=featureWorkers.js.map