// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import yaml from 'js-yaml';
import { FileSystem, Text, Async } from '@rushstack/node-core-library';
import { Colorize } from '@rushstack/terminal';
import { Stopwatch } from '../utilities/Stopwatch';
import { RushConstants } from './RushConstants';
/**
 * Default global excluded globs
 * Only used if the `<repository_root>/.mergequeueignore` does not exist
 */
const DEFAULT_GLOBAL_EXCLUDED_GLOBS = ['common/autoinstallers/**'];
async function tryReadFileLinesAsync(filePath) {
    let fileContents;
    try {
        fileContents = await FileSystem.readFileAsync(filePath);
    }
    catch (error) {
        if (!FileSystem.isNotExistError(error)) {
            throw error;
        }
    }
    if (fileContents) {
        return Text.convertToLf(fileContents).split('\n');
    }
}
export class ProjectImpactGraphGenerator {
    /**
     * Get repositoryRoot and load projects within the rush.json
     */
    constructor(terminal, rushConfiguration) {
        this._terminal = terminal;
        this._rushConfiguration = rushConfiguration;
        const { rushJsonFolder } = rushConfiguration;
        this._repositoryRoot = rushJsonFolder;
        this._projectImpactGraphFilePath = `${rushJsonFolder}/${RushConstants.projectImpactGraphFilename}`;
    }
    /**
     * Load global excluded globs
     */
    async _loadGlobalExcludedGlobsAsync() {
        const filePath = `${this._repositoryRoot}/${RushConstants.mergeQueueIgnoreFileName}`;
        return await tryReadFileLinesAsync(filePath);
    }
    /**
     * Load project excluded globs
     * @param projectRootRelativePath - project root relative path
     */
    async _tryLoadProjectExcludedGlobsAsync(projectRootRelativePath) {
        const filePath = `${this._repositoryRoot}/${projectRootRelativePath}/${RushConstants.mergeQueueIgnoreFileName}`;
        const globs = await tryReadFileLinesAsync(filePath);
        if (globs) {
            for (let i = 0; i < globs.length; i++) {
                globs[i] = `${projectRootRelativePath}/${globs[i]}`;
            }
            return globs;
        }
    }
    /**
     * Core Logic: generate project-impact-graph.yaml
     */
    async generateAsync() {
        const stopwatch = Stopwatch.start();
        const [globalExcludedGlobs = DEFAULT_GLOBAL_EXCLUDED_GLOBS, projectEntries] = await Promise.all([
            this._loadGlobalExcludedGlobsAsync(),
            Async.mapAsync(this._rushConfiguration.projects, async ({ packageName, consumingProjects, projectRelativeFolder }) => {
                const dependentList = [packageName];
                for (const consumingProject of consumingProjects) {
                    dependentList.push(consumingProject.packageName);
                }
                const projectImpactGraphProjectConfiguration = {
                    includedGlobs: [`${projectRelativeFolder}/**`],
                    dependentProjects: dependentList.sort()
                };
                const projectExcludedGlobs = await this._tryLoadProjectExcludedGlobsAsync(projectRelativeFolder);
                if (projectExcludedGlobs) {
                    projectImpactGraphProjectConfiguration.excludedGlobs = projectExcludedGlobs;
                }
                return [packageName, projectImpactGraphProjectConfiguration];
            }, { concurrency: 50 })
        ]);
        projectEntries.sort(([aName], [bName]) => aName.localeCompare(bName));
        const projects = Object.fromEntries(projectEntries);
        const content = { globalExcludedGlobs, projects };
        await FileSystem.writeFileAsync(this._projectImpactGraphFilePath, yaml.dump(content));
        stopwatch.stop();
        this._terminal.writeLine();
        this._terminal.writeLine(Colorize.green(`Generate project impact graph successfully. (${stopwatch.toString()})`));
    }
    async validateAsync() {
        // TODO: More validation other than just existence
        return await FileSystem.existsAsync(this._projectImpactGraphFilePath);
    }
}
//# sourceMappingURL=ProjectImpactGraphGenerator.js.map