'use strict';

var schematics = require('@angular-devkit/schematics');
var utility = require('@schematics/angular/utility');
var utils_messages = require('./messages.js');

/**
 * Sorts the keys of the given object.
 * @returns A new object instance with sorted keys
 */
function sortObjectByKeys(obj) {
    return Object.keys(obj)
        .sort()
        .reduce((result, key) => (result[key] = obj[key]) && result, {});
}
/**
 * Adds a package to the package.json in the given tree
 */
function addPackageToPackageJson(tree, pkg, version, devDependency = false) {
    if (tree.exists('package.json')) {
        const sourceText = tree.read('package.json').toString('utf-8');
        const json = JSON.parse(sourceText);
        const dependenciesType = devDependency ? 'devDependencies' : 'dependencies';
        const dependencies = json[dependenciesType] || {};
        if (!dependencies[pkg]) {
            dependencies[pkg] = version;
            json[dependenciesType] = sortObjectByKeys(dependencies);
        }
        tree.overwrite('package.json', JSON.stringify(json, null, 2));
    }
    return tree;
}
/**
 * Gets the version of the specified package by looking at the package.json in the given tree
 */
function getPackageVersionFromPackageJson(tree, name, includeDevDependencies = false) {
    if (!tree.exists('package.json')) {
        return null;
    }
    const packageJson = JSON.parse(tree.read('package.json').toString('utf8'));
    if (packageJson.dependencies && packageJson.dependencies[name]) {
        return packageJson.dependencies[name];
    }
    if (includeDevDependencies && packageJson.devDependencies && packageJson.devDependencies[name]) {
        return packageJson.devDependencies[name];
    }
    return null;
}
async function setupOptions(project, tree) {
    if (project) {
        const workspace = await utility.readWorkspace(tree);
        const projectWorkspace = workspace.projects.get(project);
        if (!projectWorkspace) {
            throw new schematics.SchematicsException(utils_messages.noProject(project));
        }
        return projectWorkspace;
    }
}
async function getParsingInfo(project, tree) {
    const tsPaths = new Set();
    const templatePaths = new Set();
    const projectDefinition = await setupOptions(project, tree);
    if (!projectDefinition) {
        throw new schematics.SchematicsException(utils_messages.noProject('no project'));
    }
    tree.getDir(projectDefinition.root).visit((filePath) => {
        if (filePath.endsWith('.ts')) {
            tsPaths.add(filePath);
        }
        if (filePath.endsWith('.html')) {
            templatePaths.add(filePath);
        }
    });
    return { tsPaths, templatePaths, projectDefinition };
}
/**
 * WARNING: do not change directly, since it's a copy of
 * https://github.com/angular/angular/blob/6fa8d441979fdbabb88dddd246f54587e17126e8/packages/core/schematics/utils/load_esm.ts
 *
 * This uses a dynamic import to load a module which may be ESM.
 * CommonJS code can load ESM code via a dynamic import. Unfortunately, TypeScript
 * will currently, unconditionally downlevel dynamic import into a require call.
 * require calls cannot load ESM code and will result in a runtime error. To workaround
 * this, a Function constructor is used to prevent TypeScript from changing the dynamic import.
 * Once TypeScript provides support for keeping the dynamic import this workaround can
 * be dropped.
 * This is only intended to be used with Angular framework packages.
 *
 * @param modulePath The path of the module to load.
 * @returns A Promise that resolves to the dynamically imported module.
 */
async function loadEsmModule(modulePath) {
    const namespaceObject = await new Function('modulePath', `return import(modulePath);`)(modulePath);
    // If it is not ESM then the values needed will be stored in the `default` property.
    // TODO_ESM: This can be removed once `@angular/*` packages are ESM only.
    if (namespaceObject.default) {
        return namespaceObject.default;
    }
    else {
        return namespaceObject;
    }
}

exports.addPackageToPackageJson = addPackageToPackageJson;
exports.getPackageVersionFromPackageJson = getPackageVersionFromPackageJson;
exports.getParsingInfo = getParsingInfo;
exports.loadEsmModule = loadEsmModule;
exports.setupOptions = setupOptions;
