"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveNxPlugin = resolveNxPlugin;
exports.resolveLocalNxPlugin = resolveLocalNxPlugin;
exports.getPluginPathAndName = getPluginPathAndName;
const path = require("node:path");
const node_fs_1 = require("node:fs");
const packages_1 = require("../../plugins/js/utils/packages");
const fileutils_1 = require("../../utils/fileutils");
const logger_1 = require("../../utils/logger");
const path_1 = require("../../utils/path");
const workspace_root_1 = require("../../utils/workspace-root");
const find_project_for_path_1 = require("../utils/find-project-for-path");
const retrieve_workspace_files_1 = require("../utils/retrieve-workspace-files");
let projectsWithoutInference;
let projectsWithoutInferencePromise = null;
async function resolveNxPlugin(moduleName, root, paths) {
    try {
        require.resolve(moduleName, { paths });
    }
    catch {
        // If a plugin cannot be resolved, we will need projects to resolve it
        projectsWithoutInferencePromise ??=
            (0, retrieve_workspace_files_1.retrieveProjectConfigurationsWithoutPluginInference)(root);
        projectsWithoutInference ??= await projectsWithoutInferencePromise;
    }
    const { pluginPath, name, shouldRegisterTSTranspiler } = getPluginPathAndName(moduleName, paths, projectsWithoutInference, root);
    return { pluginPath, name, shouldRegisterTSTranspiler };
}
function readPluginMainFromProjectConfiguration(plugin) {
    const { main } = Object.values(plugin.targets).find((x) => [
        '@nx/js:tsc',
        '@nrwl/js:tsc',
        '@nx/js:swc',
        '@nrwl/js:swc',
        '@nx/node:package',
        '@nrwl/node:package',
    ].includes(x.executor))?.options ||
        plugin.targets?.build?.options ||
        {};
    return main;
}
function resolveLocalNxPlugin(importPath, projects, root = workspace_root_1.workspaceRoot) {
    return lookupLocalPlugin(importPath, projects, root);
}
function getPluginPathAndName(moduleName, paths, projects, root) {
    let pluginPath;
    let shouldRegisterTSTranspiler = false;
    try {
        pluginPath = require.resolve(moduleName, {
            paths,
        });
        const extension = path.extname(pluginPath);
        shouldRegisterTSTranspiler = extension === '.ts';
    }
    catch (e) {
        if (e.code === 'MODULE_NOT_FOUND') {
            const plugin = resolveLocalNxPlugin(moduleName, projects, root);
            if (plugin) {
                shouldRegisterTSTranspiler = true;
                const main = readPluginMainFromProjectConfiguration(plugin.projectConfig);
                pluginPath = main ? path.join(root, main) : plugin.path;
            }
            else {
                logger_1.logger.error(`Plugin listed in \`nx.json\` not found: ${moduleName}`);
                throw e;
            }
        }
        else {
            throw e;
        }
    }
    const packageJsonPath = path.join(pluginPath, 'package.json');
    const { name } = !['.ts', '.js'].some((x) => path.extname(moduleName) === x) && // Not trying to point to a ts or js file
        (0, node_fs_1.existsSync)(packageJsonPath) // plugin has a package.json
        ? (0, fileutils_1.readJsonFile)(packageJsonPath) // read name from package.json
        : { name: moduleName };
    return { pluginPath, name, shouldRegisterTSTranspiler };
}
function lookupLocalPlugin(importPath, projects, root = workspace_root_1.workspaceRoot) {
    const projectConfig = findNxProjectForImportPath(importPath, projects, root);
    if (!projectConfig) {
        return null;
    }
    return { path: path.join(root, projectConfig.root), projectConfig };
}
let packageEntryPointsToProjectMap;
let wildcardEntryPointsToProjectMap;
function findNxProjectForImportPath(importPath, projects, root = workspace_root_1.workspaceRoot) {
    const tsConfigPaths = readTsConfigPaths(root);
    const possibleTsPaths = tsConfigPaths[importPath]?.map((p) => (0, path_1.normalizePath)(path.relative(root, path.join(root, p)))) ?? [];
    const projectRootMappings = new Map();
    if (possibleTsPaths.length) {
        const projectNameMap = new Map();
        for (const projectRoot in projects) {
            const project = projects[projectRoot];
            projectRootMappings.set(project.root, project.name);
            projectNameMap.set(project.name, project);
        }
        for (const tsConfigPath of possibleTsPaths) {
            const nxProject = (0, find_project_for_path_1.findProjectForPath)(tsConfigPath, projectRootMappings);
            if (nxProject) {
                return projectNameMap.get(nxProject);
            }
        }
    }
    if (!packageEntryPointsToProjectMap && !wildcardEntryPointsToProjectMap) {
        ({
            entryPointsToProjectMap: packageEntryPointsToProjectMap,
            wildcardEntryPointsToProjectMap,
        } = (0, packages_1.getWorkspacePackagesMetadata)(projects));
    }
    if (packageEntryPointsToProjectMap[importPath]) {
        return packageEntryPointsToProjectMap[importPath];
    }
    const project = (0, packages_1.matchImportToWildcardEntryPointsToProjectMap)(wildcardEntryPointsToProjectMap, importPath);
    if (project) {
        return project;
    }
    logger_1.logger.verbose('Unable to find local plugin', possibleTsPaths, projectRootMappings);
    throw new Error('Unable to resolve local plugin with import path ' + importPath);
}
let tsconfigPaths;
function readTsConfigPaths(root = workspace_root_1.workspaceRoot) {
    if (!tsconfigPaths) {
        const tsconfigPath = ['tsconfig.base.json', 'tsconfig.json']
            .map((x) => path.join(root, x))
            .filter((x) => (0, node_fs_1.existsSync)(x))[0];
        if (!tsconfigPath) {
            throw new Error('unable to find tsconfig.base.json or tsconfig.json');
        }
        const { compilerOptions } = (0, fileutils_1.readJsonFile)(tsconfigPath);
        tsconfigPaths = compilerOptions?.paths;
    }
    return tsconfigPaths ?? {};
}
