"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.ApprovedPackagesConfiguration = exports.ApprovedPackagesItem = void 0;
const path = __importStar(require("node:path"));
const node_core_library_1 = require("@rushstack/node-core-library");
const JsonSchemaUrls_1 = require("../logic/JsonSchemaUrls");
const approved_packages_schema_json_1 = __importDefault(require("../schemas/approved-packages.schema.json"));
const RushConstants_1 = require("../logic/RushConstants");
/**
 * An item returned by ApprovedPackagesConfiguration
 * @public
 */
class ApprovedPackagesItem {
    /**
     * @internal
     */
    constructor(packageName) {
        /**
         * The project categories that are allowed to use this package.
         */
        this.allowedCategories = new Set();
        this.packageName = packageName;
    }
}
exports.ApprovedPackagesItem = ApprovedPackagesItem;
/**
 * This represents the JSON file specified via the "approvedPackagesFile" option in rush.json.
 * @public
 */
class ApprovedPackagesConfiguration {
    constructor(jsonFilename) {
        this.items = [];
        this._itemsByName = new Map();
        this._jsonFilename = jsonFilename;
        this.clear();
    }
    /**
     * Clears all the settings, returning to an empty state.
     */
    clear() {
        this._itemsByName.clear();
        this._loadedJson = {
            // Ensure this comes first in the key ordering
            $schema: '',
            packages: []
        };
    }
    getItemByName(packageName) {
        return this._itemsByName.get(packageName);
    }
    addOrUpdatePackage(packageName, reviewCategory) {
        let changed = false;
        let item = this._itemsByName.get(packageName);
        if (!item) {
            item = new ApprovedPackagesItem(packageName);
            this._addItem(item);
            changed = true;
        }
        if (reviewCategory && !item.allowedCategories.has(reviewCategory)) {
            item.allowedCategories.add(reviewCategory);
            changed = true;
        }
        return changed;
    }
    /**
     * If the file exists, calls loadFromFile().
     */
    tryLoadFromFile(approvedPackagesPolicyEnabled) {
        if (!node_core_library_1.FileSystem.exists(this._jsonFilename)) {
            return false;
        }
        this.loadFromFile();
        if (!approvedPackagesPolicyEnabled) {
            // eslint-disable-next-line no-console
            console.log(`Warning: Ignoring "${path.basename(this._jsonFilename)}" because the` +
                ` "approvedPackagesPolicy" setting was not specified in ${RushConstants_1.RushConstants.rushJsonFilename}`);
        }
        return false;
    }
    /**
     * Loads the configuration data from the filename that was passed to the constructor.
     */
    loadFromFile() {
        const approvedPackagesJson = node_core_library_1.JsonFile.loadAndValidate(this._jsonFilename, ApprovedPackagesConfiguration._jsonSchema);
        this.clear();
        for (const browserPackage of approvedPackagesJson.packages) {
            this._addItemJson(browserPackage, this._jsonFilename);
        }
    }
    /**
     * Loads the configuration data to the filename that was passed to the constructor.
     */
    saveToFile() {
        // Update the JSON structure that we already loaded, preserving any existing state
        // (which passed schema validation).
        // eslint-disable-next-line dot-notation
        this._loadedJson['$schema'] = JsonSchemaUrls_1.JsonSchemaUrls.approvedPackages;
        this._loadedJson.packages = [];
        this.items.sort((a, b) => {
            return a.packageName.localeCompare(b.packageName);
        });
        for (const item of this.items) {
            // Sort the items from the set.
            const allowedCategories = Array.from(item.allowedCategories);
            allowedCategories.sort();
            const itemJson = {
                name: item.packageName,
                allowedCategories: allowedCategories
            };
            this._loadedJson.packages.push(itemJson);
        }
        // Save the file
        let body = node_core_library_1.JsonFile.stringify(this._loadedJson);
        // Unindent the allowedCategories array to improve readability
        body = body.replace(/("allowedCategories": +\[)([^\]]+)/g, (substring, ...args) => {
            return args[0] + args[1].replace(/\s+/g, ' ');
        });
        // Add a header
        body = '// DO NOT ADD COMMENTS IN THIS FILE.  They will be lost when the Rush tool resaves it.\n' + body;
        node_core_library_1.FileSystem.writeFile(this._jsonFilename, body, {
            convertLineEndings: node_core_library_1.NewlineKind.CrLf
        });
    }
    /**
     * Helper function only used by the constructor when loading the file.
     */
    _addItemJson(itemJson, jsonFilename) {
        if (this._itemsByName.has(itemJson.name)) {
            throw new Error(`Error loading package review file ${jsonFilename}:\n` +
                ` the name "${itemJson.name}" appears more than once`);
        }
        const item = new ApprovedPackagesItem(itemJson.name);
        if (itemJson.allowedCategories) {
            for (const allowedCategory of itemJson.allowedCategories) {
                item.allowedCategories.add(allowedCategory);
            }
        }
        this._addItem(item);
    }
    /**
     * Helper function that adds an already created ApprovedPackagesItem to the
     * list and set.
     */
    _addItem(item) {
        if (this._itemsByName.has(item.packageName)) {
            throw new node_core_library_1.InternalError('Duplicate key');
        }
        this.items.push(item);
        this._itemsByName.set(item.packageName, item);
    }
}
exports.ApprovedPackagesConfiguration = ApprovedPackagesConfiguration;
ApprovedPackagesConfiguration._jsonSchema = node_core_library_1.JsonSchema.fromLoadedObject(approved_packages_schema_json_1.default);
//# sourceMappingURL=ApprovedPackagesConfiguration.js.map