"use strict";
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
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 () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PluginLoaderBase = void 0;
const path = __importStar(require("node:path"));
const node_core_library_1 = require("@rushstack/node-core-library");
const CommandLineConfiguration_1 = require("../../api/CommandLineConfiguration");
const RushConstants_1 = require("../../logic/RushConstants");
const RushSdk_1 = require("./RushSdk");
const rush_plugin_manifest_schema_json_1 = __importDefault(require("../../schemas/rush-plugin-manifest.schema.json"));
class PluginLoaderBase {
    constructor({ pluginConfiguration, rushConfiguration, terminal }) {
        this.packageName = pluginConfiguration.packageName;
        this.pluginName = pluginConfiguration.pluginName;
        this._rushConfiguration = rushConfiguration;
        this._terminal = terminal;
    }
    load() {
        const resolvedPluginPath = this._resolvePlugin();
        if (!resolvedPluginPath) {
            return undefined;
        }
        const pluginOptions = this._getPluginOptions();
        RushSdk_1.RushSdk.ensureInitialized();
        return this._loadAndValidatePluginPackage(resolvedPluginPath, pluginOptions);
    }
    get pluginManifest() {
        return this._getRushPluginManifest();
    }
    getCommandLineConfiguration() {
        const commandLineJsonFilePath = this._getCommandLineJsonFilePath();
        if (!commandLineJsonFilePath) {
            return undefined;
        }
        const commandLineConfiguration = CommandLineConfiguration_1.CommandLineConfiguration.tryLoadFromFile(commandLineJsonFilePath);
        if (!commandLineConfiguration) {
            return undefined;
        }
        for (const additionalPathFolder of this._getCommandLineAdditionalPathFolders().reverse()) {
            commandLineConfiguration.prependAdditionalPathFolder(additionalPathFolder);
        }
        commandLineConfiguration.shellCommandTokenContext = {
            packageFolder: this.packageFolder
        };
        return commandLineConfiguration;
    }
    _getCommandLineAdditionalPathFolders() {
        return [
            // Example: `@microsoft/rush-lib/node_modules/<packageName>/node_modules/.bin`
            // Example: `common/autoinstaller/plugins/node_modules/<packageName>/node_modules/.bin`
            path.join(this.packageFolder, 'node_modules', '.bin')
        ];
    }
    _getCommandLineJsonFilePath() {
        const { commandLineJsonFilePath } = this._getRushPluginManifest();
        if (!commandLineJsonFilePath) {
            return undefined;
        }
        return path.join(this.packageFolder, commandLineJsonFilePath);
    }
    _loadAndValidatePluginPackage(resolvedPluginPath, options) {
        let pluginPackage;
        try {
            const loadedPluginPackage = require(resolvedPluginPath);
            pluginPackage = loadedPluginPackage.default || loadedPluginPackage;
        }
        catch (e) {
            throw new node_core_library_1.InternalError(`Error loading rush plugin from "${resolvedPluginPath}": ${e}`);
        }
        if (!pluginPackage) {
            throw new node_core_library_1.InternalError(`Rush plugin loaded from "${resolvedPluginPath}" is null or undefined.`);
        }
        this._terminal.writeVerboseLine(`Loaded rush plugin from "${resolvedPluginPath}"`);
        const plugin = new pluginPackage(options);
        if (!plugin.apply || typeof pluginPackage.apply !== 'function') {
            throw new node_core_library_1.InternalError(`Rush plugin must define an "apply" function. The plugin loaded from "${resolvedPluginPath}" ` +
                'either doesn\'t define an "apply" property, or its value isn\'t a function.');
        }
        return plugin;
    }
    _resolvePlugin() {
        const entryPoint = this._getRushPluginManifest().entryPoint;
        if (!entryPoint) {
            return undefined;
        }
        const packageFolder = this.packageFolder;
        const modulePath = path.join(packageFolder, entryPoint);
        if (!node_core_library_1.FileSystem.exists(modulePath)) {
            throw new node_core_library_1.InternalError(`Unable to find entry point "${modulePath}" for rush plugin "${this.pluginName}".`);
        }
        return modulePath;
    }
    _getPluginOptions() {
        const optionsJsonFilePath = this._getPluginOptionsJsonFilePath();
        const optionsSchema = this._getRushPluginOptionsSchema();
        let pluginOptions = {};
        try {
            pluginOptions = node_core_library_1.JsonFile.load(optionsJsonFilePath);
        }
        catch (e) {
            if (node_core_library_1.FileSystem.isFileDoesNotExistError(e)) {
                return {};
            }
            throw e;
        }
        if (optionsSchema) {
            optionsSchema.validateObject(pluginOptions, optionsJsonFilePath);
        }
        return pluginOptions;
    }
    _getPluginOptionsJsonFilePath() {
        return path.join(this._rushConfiguration.rushPluginOptionsFolder, `${this.pluginName}.json`);
    }
    _getRushPluginOptionsSchema() {
        const optionsSchema = this._getRushPluginManifest().optionsSchema;
        if (!optionsSchema) {
            return undefined;
        }
        const optionsSchemaFilePath = path.join(this.packageFolder, optionsSchema);
        return node_core_library_1.JsonSchema.fromFile(optionsSchemaFilePath);
    }
    _getRushPluginManifest() {
        if (!this._manifestCache) {
            const packageName = this.packageName;
            const pluginName = this.pluginName;
            const manifestPath = this._getManifestPath();
            if (!node_core_library_1.FileSystem.exists(manifestPath)) {
                throw new Error(`Manifest for rush plugin package ${packageName} not found.\nPlease run 'rush update' first.`);
            }
            const rushPluginManifestJson = node_core_library_1.JsonFile.loadAndValidate(manifestPath, PluginLoaderBase._jsonSchema);
            const pluginManifest = rushPluginManifestJson.plugins.find((item) => item.pluginName === pluginName);
            if (!pluginManifest) {
                throw new Error(`${pluginName} is not provided by Rush plugin package "${packageName}"`);
            }
            this._manifestCache = pluginManifest;
        }
        return this._manifestCache;
    }
    _getManifestPath() {
        return path.join(this.packageFolder, RushConstants_1.RushConstants.rushPluginManifestFilename);
    }
}
exports.PluginLoaderBase = PluginLoaderBase;
PluginLoaderBase._jsonSchema = node_core_library_1.JsonSchema.fromLoadedObject(rush_plugin_manifest_schema_json_1.default);
//# sourceMappingURL=PluginLoaderBase.js.map