'use strict';
/**
 * @license Angular v20.0.0-next.5
 * (c) 2010-2025 Google LLC. https://angular.io/
 * License: MIT
 */
'use strict';

var p = require('path');
var ts = require('typescript');

function _interopNamespaceDefault(e) {
    var n = Object.create(null);
    if (e) {
        Object.keys(e).forEach(function (k) {
            if (k !== 'default') {
                var d = Object.getOwnPropertyDescriptor(e, k);
                Object.defineProperty(n, k, d.get ? d : {
                    enumerable: true,
                    get: function () { return e[k]; }
                });
            }
        });
    }
    n.default = e;
    return Object.freeze(n);
}

var p__namespace = /*#__PURE__*/_interopNamespaceDefault(p);

function parseTsconfigFile(tsconfigPath, basePath) {
    const { config } = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
    const parseConfigHost = {
        useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
        fileExists: ts.sys.fileExists,
        readDirectory: ts.sys.readDirectory,
        readFile: ts.sys.readFile,
    };
    // Throw if incorrect arguments are passed to this function. Passing relative base paths
    // results in root directories not being resolved and in later type checking runtime errors.
    // More details can be found here: https://github.com/microsoft/TypeScript/issues/37731.
    if (!p__namespace.isAbsolute(basePath)) {
        throw Error('Unexpected relative base path has been specified.');
    }
    return ts.parseJsonConfigFileContent(config, parseConfigHost, basePath, {});
}

/**
 * Creates a TypeScript program instance for a TypeScript project within
 * the virtual file system tree.
 * @param tree Virtual file system tree that contains the source files.
 * @param tsconfigPath Virtual file system path that resolves to the TypeScript project.
 * @param basePath Base path for the virtual file system tree.
 * @param fakeFileRead Optional file reader function. Can be used to overwrite files in
 *   the TypeScript program, or to add in-memory files (e.g. to add global types).
 * @param additionalFiles Additional file paths that should be added to the program.
 */
function createMigrationProgram(tree, tsconfigPath, basePath, fakeFileRead, additionalFiles) {
    const { rootNames, options, host } = createProgramOptions(tree, tsconfigPath, basePath, fakeFileRead);
    return ts.createProgram(rootNames, options, host);
}
/**
 * Creates the options necessary to instantiate a TypeScript program.
 * @param tree Virtual file system tree that contains the source files.
 * @param tsconfigPath Virtual file system path that resolves to the TypeScript project.
 * @param basePath Base path for the virtual file system tree.
 * @param fakeFileRead Optional file reader function. Can be used to overwrite files in
 *   the TypeScript program, or to add in-memory files (e.g. to add global types).
 * @param additionalFiles Additional file paths that should be added to the program.
 * @param optionOverrides Overrides of the parsed compiler options.
 */
function createProgramOptions(tree, tsconfigPath, basePath, fakeFileRead, additionalFiles, optionOverrides) {
    // Resolve the tsconfig path to an absolute path. This is needed as TypeScript otherwise
    // is not able to resolve root directories in the given tsconfig. More details can be found
    // in the following issue: https://github.com/microsoft/TypeScript/issues/37731.
    tsconfigPath = p.resolve(basePath, tsconfigPath);
    const parsed = parseTsconfigFile(tsconfigPath, p.dirname(tsconfigPath));
    const options = optionOverrides ? { ...parsed.options, ...optionOverrides } : parsed.options;
    const host = createMigrationCompilerHost(tree, options, basePath, fakeFileRead);
    return { rootNames: parsed.fileNames.concat([]), options, host };
}
function createMigrationCompilerHost(tree, options, basePath, fakeRead) {
    const host = ts.createCompilerHost(options, true);
    const defaultReadFile = host.readFile;
    // We need to overwrite the host "readFile" method, as we want the TypeScript
    // program to be based on the file contents in the virtual file tree. Otherwise
    // if we run multiple migrations we might have intersecting changes and
    // source files.
    host.readFile = (fileName) => {
        const treeRelativePath = p.relative(basePath, fileName);
        let result = fakeRead?.(treeRelativePath);
        if (typeof result !== 'string') {
            // If the relative path resolved to somewhere outside of the tree, fall back to
            // TypeScript's default file reading function since the `tree` will throw an error.
            result = treeRelativePath.startsWith('..')
                ? defaultReadFile.call(host, fileName)
                : tree.read(treeRelativePath)?.toString();
        }
        // Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset,
        // which breaks the CLI UpdateRecorder.
        // See: https://github.com/angular/angular/pull/30719
        return typeof result === 'string' ? result.replace(/^\uFEFF/, '') : undefined;
    };
    return host;
}
/**
 * Checks whether a file can be migrate by our automated migrations.
 * @param basePath Absolute path to the project.
 * @param sourceFile File being checked.
 * @param program Program that includes the source file.
 */
function canMigrateFile(basePath, sourceFile, program) {
    // We shouldn't migrate .d.ts files, files from an external library or type checking files.
    if (sourceFile.fileName.endsWith('.ngtypecheck.ts') ||
        sourceFile.isDeclarationFile ||
        program.isSourceFileFromExternalLibrary(sourceFile)) {
        return false;
    }
    // Our migrations are set up to create a `Program` from the project's tsconfig and to migrate all
    // the files within the program. This can include files that are outside of the Angular CLI
    // project. We can't migrate files outside of the project, because our file system interactions
    // go through the CLI's `Tree` which assumes that all files are within the project. See:
    // https://github.com/angular/angular-cli/blob/0b0961c9c233a825b6e4bb59ab7f0790f9b14676/packages/angular_devkit/schematics/src/tree/host-tree.ts#L131
    return !p.relative(basePath, sourceFile.fileName).startsWith('..');
}

exports.canMigrateFile = canMigrateFile;
exports.createMigrationProgram = createMigrationProgram;
exports.createProgramOptions = createProgramOptions;
