"use strict";
/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */
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.createCompilerPlugin = createCompilerPlugin;
const node_assert_1 = __importDefault(require("node:assert"));
const node_crypto_1 = require("node:crypto");
const path = __importStar(require("node:path"));
const environment_options_1 = require("../../../utils/environment-options");
const compilation_1 = require("../../angular/compilation");
const javascript_transformer_1 = require("../javascript-transformer");
const load_result_cache_1 = require("../load-result-cache");
const profiling_1 = require("../profiling");
const compilation_state_1 = require("./compilation-state");
const file_reference_tracker_1 = require("./file-reference-tracker");
const jit_plugin_callbacks_1 = require("./jit-plugin-callbacks");
const rewrite_bazel_paths_1 = require("./rewrite-bazel-paths");
// eslint-disable-next-line max-lines-per-function
function createCompilerPlugin(pluginOptions, compilationOrFactory, stylesheetBundler) {
    return {
        name: 'angular-compiler',
        // eslint-disable-next-line max-lines-per-function
        async setup(build) {
            let setupWarnings = [];
            const preserveSymlinks = build.initialOptions.preserveSymlinks;
            // Initialize a worker pool for JavaScript transformations.
            // Webcontainers currently do not support this persistent cache store.
            let cacheStore;
            if (pluginOptions.sourceFileCache?.persistentCachePath && !process.versions.webcontainer) {
                try {
                    const { LmbdCacheStore } = await Promise.resolve().then(() => __importStar(require('../lmdb-cache-store')));
                    cacheStore = new LmbdCacheStore(path.join(pluginOptions.sourceFileCache.persistentCachePath, 'angular-compiler.db'));
                }
                catch (e) {
                    setupWarnings.push({
                        text: 'Unable to initialize JavaScript cache storage.',
                        location: null,
                        notes: [
                            // Only show first line of lmdb load error which has platform support listed
                            { text: e?.message.split('\n')[0] ?? `${e}` },
                            {
                                text: 'This will not affect the build output content but may result in slower builds.',
                            },
                        ],
                    });
                }
            }
            const javascriptTransformer = new javascript_transformer_1.JavaScriptTransformer({
                sourcemap: !!pluginOptions.sourcemap,
                thirdPartySourcemaps: pluginOptions.thirdPartySourcemaps,
                advancedOptimizations: pluginOptions.advancedOptimizations,
                jit: pluginOptions.jit || pluginOptions.includeTestMetadata,
            }, environment_options_1.maxWorkers, cacheStore?.createCache('jstransformer'));
            // Setup defines based on the values used by the Angular compiler-cli
            build.initialOptions.define ??= {};
            build.initialOptions.define['ngI18nClosureMode'] ??= 'false';
            // The factory is only relevant for compatibility purposes with the private API.
            // TODO: Update private API in the next major to allow compilation function factory removal here.
            const compilation = typeof compilationOrFactory === 'function'
                ? await compilationOrFactory()
                : compilationOrFactory;
            // The in-memory cache of TypeScript file outputs will be used during the build in `onLoad` callbacks for TS files.
            // A string value indicates direct TS/NG output and a Uint8Array indicates fully transformed code.
            const typeScriptFileCache = pluginOptions.sourceFileCache?.typeScriptFileCache ??
                new Map();
            // The resources from component stylesheets and web workers that will be added to the build results output files
            const additionalResults = new Map();
            // Compilation is initially assumed to have errors until emitted
            let hasCompilationErrors = true;
            // Determines if TypeScript should process JavaScript files based on tsconfig `allowJs` option
            let shouldTsIgnoreJs = true;
            // Determines if transpilation should be handle by TypeScript or esbuild
            let useTypeScriptTranspilation = true;
            let sharedTSCompilationState;
            // To fully invalidate files, track resource referenced files and their referencing source
            const referencedFileTracker = new file_reference_tracker_1.FileReferenceTracker();
            // eslint-disable-next-line max-lines-per-function
            build.onStart(async () => {
                sharedTSCompilationState = (0, compilation_state_1.getSharedCompilationState)();
                if (!(compilation instanceof compilation_1.NoopCompilation)) {
                    sharedTSCompilationState.markAsInProgress();
                }
                const result = {
                    warnings: setupWarnings,
                };
                // Reset debug performance tracking
                (0, profiling_1.resetCumulativeDurations)();
                // Update the reference tracker and generate a full set of modified files for the
                // Angular compiler which does not have direct knowledge of transitive resource
                // dependencies or web worker processing.
                let modifiedFiles;
                if (!(compilation instanceof compilation_1.NoopCompilation) &&
                    pluginOptions.sourceFileCache?.modifiedFiles.size) {
                    // TODO: Differentiate between changed input files and stale output files
                    modifiedFiles = referencedFileTracker.update(pluginOptions.sourceFileCache.modifiedFiles);
                    pluginOptions.sourceFileCache.invalidate(modifiedFiles);
                    // External runtime styles are invalidated and rebuilt at the beginning of a rebuild to avoid
                    // the need to execute the application bundler for component style only changes.
                    if (!pluginOptions.externalRuntimeStyles) {
                        stylesheetBundler.invalidate(modifiedFiles);
                    }
                    // Remove any stale additional results based on modified files
                    modifiedFiles.forEach((file) => additionalResults.delete(file));
                }
                if (compilation.update && pluginOptions.sourceFileCache?.modifiedFiles.size) {
                    await compilation.update(modifiedFiles ?? pluginOptions.sourceFileCache.modifiedFiles);
                }
                // Create Angular compiler host options
                const hostOptions = {
                    fileReplacements: pluginOptions.fileReplacements,
                    modifiedFiles,
                    sourceFileCache: pluginOptions.sourceFileCache,
                    async transformStylesheet(data, containingFile, stylesheetFile, order, className) {
                        let stylesheetResult;
                        let resultSource = stylesheetFile ?? containingFile;
                        // Stylesheet file only exists for external stylesheets
                        if (stylesheetFile) {
                            stylesheetResult = await stylesheetBundler.bundleFile(stylesheetFile);
                        }
                        else {
                            stylesheetResult = await stylesheetBundler.bundleInline(data, containingFile, 
                            // Inline stylesheets from a template style element are always CSS; Otherwise, use default.
                            containingFile.endsWith('.html') ? 'css' : undefined, 
                            // When external runtime styles are enabled, an identifier for the style that does not change
                            // based on the content is required to avoid emitted JS code changes. Any JS code changes will
                            // invalid the output and force a full page reload for HMR cases. The containing file and order
                            // of the style within the containing file is used.
                            pluginOptions.externalRuntimeStyles
                                ? (0, node_crypto_1.createHash)('sha256')
                                    .update(containingFile)
                                    .update((order ?? 0).toString())
                                    .update(className ?? '')
                                    .digest('hex')
                                : undefined);
                            // Adjust result source for inline styles.
                            // There may be multiple inline styles with the same containing file and to ensure that the results
                            // do not overwrite each other the result source identifier needs to be unique for each. The class
                            // name and order fields can be used for this. The structure is arbitrary as long as it is unique.
                            resultSource += `?class=${className}&order=${order}`;
                        }
                        (result.warnings ??= []).push(...stylesheetResult.warnings);
                        if (stylesheetResult.errors) {
                            (result.errors ??= []).push(...stylesheetResult.errors);
                            return '';
                        }
                        const { contents, outputFiles, metafile, referencedFiles } = stylesheetResult;
                        additionalResults.set(resultSource, {
                            outputFiles,
                            metafile,
                        });
                        if (referencedFiles) {
                            referencedFileTracker.add(containingFile, referencedFiles);
                            if (stylesheetFile) {
                                // Angular AOT compiler needs modified direct resource files to correctly invalidate its analysis
                                referencedFileTracker.add(stylesheetFile, referencedFiles);
                            }
                        }
                        return contents;
                    },
                    processWebWorker(workerFile, containingFile) {
                        const fullWorkerPath = path.join(path.dirname(containingFile), workerFile);
                        // The synchronous API must be used due to the TypeScript compilation currently being
                        // fully synchronous and this process callback being called from within a TypeScript
                        // transformer.
                        const workerResult = bundleWebWorker(build, pluginOptions, fullWorkerPath);
                        (result.warnings ??= []).push(...workerResult.warnings);
                        if (workerResult.errors.length > 0) {
                            (result.errors ??= []).push(...workerResult.errors);
                            // Track worker file errors to allow rebuilds on changes
                            referencedFileTracker.add(containingFile, workerResult.errors
                                .map((error) => error.location?.file)
                                .filter((file) => !!file)
                                .map((file) => path.join(build.initialOptions.absWorkingDir ?? '', file)));
                            additionalResults.set(fullWorkerPath, { errors: result.errors });
                            // Return the original path if the build failed
                            return workerFile;
                        }
                        (0, node_assert_1.default)('outputFiles' in workerResult, 'Invalid web worker bundle result.');
                        additionalResults.set(fullWorkerPath, {
                            outputFiles: workerResult.outputFiles,
                            metafile: workerResult.metafile,
                        });
                        referencedFileTracker.add(containingFile, Object.keys(workerResult.metafile.inputs).map((input) => path.join(build.initialOptions.absWorkingDir ?? '', input)));
                        // Return bundled worker file entry name to be used in the built output
                        const workerCodeFile = workerResult.outputFiles.find((file) => /^worker-[A-Z0-9]{8}.[cm]?js$/.test(path.basename(file.path)));
                        (0, node_assert_1.default)(workerCodeFile, 'Web Worker bundled code file should always be present.');
                        const workerCodePath = path.relative(build.initialOptions.outdir ?? '', workerCodeFile.path);
                        return workerCodePath.replaceAll('\\', '/');
                    },
                };
                // Initialize the Angular compilation for the current build.
                // In watch mode, previous build state will be reused.
                let referencedFiles;
                let externalStylesheets;
                try {
                    const initializationResult = await compilation.initialize(pluginOptions.tsconfig, hostOptions, createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks, build.initialOptions.conditions));
                    shouldTsIgnoreJs = !initializationResult.compilerOptions.allowJs;
                    // Isolated modules option ensures safe non-TypeScript transpilation.
                    // Typescript printing support for sourcemaps is not yet integrated.
                    useTypeScriptTranspilation =
                        !initializationResult.compilerOptions.isolatedModules ||
                            !!initializationResult.compilerOptions.sourceMap ||
                            !!initializationResult.compilerOptions.inlineSourceMap;
                    referencedFiles = initializationResult.referencedFiles;
                    externalStylesheets = initializationResult.externalStylesheets;
                    if (initializationResult.templateUpdates) {
                        // Propagate any template updates
                        initializationResult.templateUpdates.forEach((value, key) => pluginOptions.templateUpdates?.set(key, value));
                    }
                }
                catch (error) {
                    (result.errors ??= []).push({
                        text: 'Angular compilation initialization failed.',
                        location: null,
                        notes: [
                            {
                                text: error instanceof Error ? (error.stack ?? error.message) : `${error}`,
                                location: null,
                            },
                        ],
                    });
                    // Initialization failure prevents further compilation steps
                    hasCompilationErrors = true;
                    return result;
                }
                if (compilation instanceof compilation_1.NoopCompilation) {
                    hasCompilationErrors = await sharedTSCompilationState.waitUntilReady;
                    return result;
                }
                if (externalStylesheets) {
                    // Process any new external stylesheets
                    for (const [stylesheetFile, externalId] of externalStylesheets) {
                        await bundleExternalStylesheet(stylesheetBundler, stylesheetFile, externalId, result, additionalResults);
                    }
                }
                // Update TypeScript file output cache for all affected files
                try {
                    await (0, profiling_1.profileAsync)('NG_EMIT_TS', async () => {
                        for (const { filename, contents } of await compilation.emitAffectedFiles()) {
                            typeScriptFileCache.set(path.normalize(filename), contents);
                        }
                    });
                }
                catch (error) {
                    (result.errors ??= []).push({
                        text: 'Angular compilation emit failed.',
                        location: null,
                        notes: [
                            {
                                text: error instanceof Error ? (error.stack ?? error.message) : `${error}`,
                                location: null,
                            },
                        ],
                    });
                }
                const diagnostics = await compilation.diagnoseFiles(environment_options_1.useTypeChecking ? compilation_1.DiagnosticModes.All : compilation_1.DiagnosticModes.All & ~compilation_1.DiagnosticModes.Semantic);
                if (diagnostics.errors?.length) {
                    (result.errors ??= []).push(...diagnostics.errors);
                }
                if (diagnostics.warnings?.length) {
                    (result.warnings ??= []).push(...diagnostics.warnings);
                }
                // Add errors from failed additional results.
                // This must be done after emit to capture latest web worker results.
                for (const { errors } of additionalResults.values()) {
                    if (errors) {
                        (result.errors ??= []).push(...errors);
                    }
                }
                // Store referenced files for updated file watching if enabled
                if (pluginOptions.sourceFileCache) {
                    pluginOptions.sourceFileCache.referencedFiles = [
                        ...referencedFiles,
                        ...referencedFileTracker.referencedFiles,
                    ];
                }
                hasCompilationErrors = !!result.errors?.length;
                // Reset the setup warnings so that they are only shown during the first build.
                setupWarnings = undefined;
                sharedTSCompilationState.markAsReady(hasCompilationErrors);
                return result;
            });
            build.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, async (args) => {
                const request = (0, rewrite_bazel_paths_1.rewriteForBazel)(path.normalize(pluginOptions.fileReplacements?.[path.normalize(args.path)] ?? args.path));
                const isJS = /\.[cm]?js$/.test(request);
                // Skip TS load attempt if JS TypeScript compilation not enabled and file is JS
                if (shouldTsIgnoreJs && isJS) {
                    return undefined;
                }
                // The filename is currently used as a cache key. Since the cache is memory only,
                // the options cannot change and do not need to be represented in the key. If the
                // cache is later stored to disk, then the options that affect transform output
                // would need to be added to the key as well as a check for any change of content.
                let contents = typeScriptFileCache.get(request);
                if (contents === undefined) {
                    // If the Angular compilation had errors the file may not have been emitted.
                    // To avoid additional errors about missing files, return empty contents.
                    if (hasCompilationErrors) {
                        return { contents: '', loader: 'js' };
                    }
                    // No TS result indicates the file is not part of the TypeScript program.
                    // If allowJs is enabled and the file is JS then defer to the next load hook.
                    if (!shouldTsIgnoreJs && isJS) {
                        return undefined;
                    }
                    // Otherwise return an error
                    return {
                        errors: [
                            createMissingFileError(request, args.path, build.initialOptions.absWorkingDir ?? ''),
                        ],
                    };
                }
                else if (typeof contents === 'string' && (useTypeScriptTranspilation || isJS)) {
                    // A string indicates untransformed output from the TS/NG compiler.
                    // This step is unneeded when using esbuild transpilation.
                    const sideEffects = await hasSideEffects(request);
                    const instrumentForCoverage = pluginOptions.instrumentForCoverage?.(request);
                    contents = await javascriptTransformer.transformData(request, contents, true /* skipLinker */, sideEffects, instrumentForCoverage);
                    // Store as the returned Uint8Array to allow caching the fully transformed code
                    typeScriptFileCache.set(request, contents);
                }
                let loader;
                if (useTypeScriptTranspilation || isJS) {
                    // TypeScript has transpiled to JS or is already JS
                    loader = 'js';
                }
                else if (request.at(-1) === 'x') {
                    // TSX and TS have different syntax rules. Only set if input is a TSX file.
                    loader = 'tsx';
                }
                else {
                    // Otherwise, directly bundle TS
                    loader = 'ts';
                }
                return {
                    contents,
                    loader,
                    resolveDir: path.dirname(request),
                };
            });
            build.onLoad({ filter: /\.[cm]?js$/ }, (0, load_result_cache_1.createCachedLoad)(pluginOptions.loadResultCache, async (args) => {
                let request = (0, rewrite_bazel_paths_1.rewriteForBazel)(args.path);
                if (pluginOptions.fileReplacements) {
                    const replacement = pluginOptions.fileReplacements[path.normalize(args.path)];
                    if (replacement) {
                        request = path.normalize(replacement);
                    }
                }
                return (0, profiling_1.profileAsync)('NG_EMIT_JS*', async () => {
                    const sideEffects = await hasSideEffects(request);
                    const contents = await javascriptTransformer.transformFile(request, pluginOptions.jit, sideEffects);
                    return {
                        contents,
                        loader: 'js',
                        resolveDir: path.dirname(request),
                        watchFiles: request !== args.path ? [request] : undefined,
                    };
                }, true);
            }));
            // Add a load handler if there are file replacement option entries for JSON files
            if (pluginOptions.fileReplacements &&
                Object.keys(pluginOptions.fileReplacements).some((value) => value.endsWith('.json'))) {
                build.onLoad({ filter: /\.json$/ }, (0, load_result_cache_1.createCachedLoad)(pluginOptions.loadResultCache, async (args) => {
                    const replacement = pluginOptions.fileReplacements?.[path.normalize(args.path)];
                    if (replacement) {
                        return {
                            contents: await Promise.resolve().then(() => __importStar(require('node:fs/promises'))).then(({ readFile }) => readFile(path.normalize(replacement))),
                            loader: 'json',
                            watchFiles: [replacement],
                        };
                    }
                    // If no replacement defined, let esbuild handle it directly
                    return null;
                }));
            }
            // Setup bundling of component templates and stylesheets when in JIT mode
            if (pluginOptions.jit) {
                (0, jit_plugin_callbacks_1.setupJitPluginCallbacks)(build, stylesheetBundler, additionalResults, pluginOptions.loadResultCache);
            }
            build.onEnd((result) => {
                // Ensure other compilations are unblocked if the main compilation throws during start
                sharedTSCompilationState?.markAsReady(hasCompilationErrors);
                for (const { outputFiles, metafile } of additionalResults.values()) {
                    // Add any additional output files to the main output files
                    if (outputFiles?.length) {
                        result.outputFiles?.push(...outputFiles);
                    }
                    // Combine additional metafiles with main metafile
                    if (result.metafile && metafile) {
                        // Append the existing object, by appending to it we prevent unnecessary new objections creations with spread
                        // mitigating significant performance overhead for large apps.
                        // See: https://bugs.chromium.org/p/v8/issues/detail?id=11536
                        Object.assign(result.metafile.inputs, metafile.inputs);
                        Object.assign(result.metafile.outputs, metafile.outputs);
                    }
                }
                (0, profiling_1.logCumulativeDurations)();
            });
            build.onDispose(() => {
                sharedTSCompilationState?.dispose();
                void compilation.close?.();
                void cacheStore?.close();
            });
            /**
             * Checks if the file has side-effects when `advancedOptimizations` is enabled.
             */
            async function hasSideEffects(path) {
                if (!pluginOptions.advancedOptimizations) {
                    return undefined;
                }
                const { sideEffects } = await build.resolve(path, {
                    kind: 'import-statement',
                    resolveDir: build.initialOptions.absWorkingDir ?? '',
                });
                return sideEffects;
            }
        },
    };
}
async function bundleExternalStylesheet(stylesheetBundler, stylesheetFile, externalId, result, additionalResults) {
    const styleResult = await stylesheetBundler.bundleFile(stylesheetFile, externalId);
    (result.warnings ??= []).push(...styleResult.warnings);
    if (styleResult.errors) {
        (result.errors ??= []).push(...styleResult.errors);
    }
    else {
        const { outputFiles, metafile } = styleResult;
        // Clear inputs to prevent triggering a rebuild of the application code for component
        // stylesheet file only changes when the dev server enables the internal-only external
        // stylesheet option. This does not affect builds since only the dev server can enable
        // the internal option.
        metafile.inputs = {};
        additionalResults.set(stylesheetFile, {
            outputFiles,
            metafile,
        });
    }
}
function createCompilerOptionsTransformer(setupWarnings, pluginOptions, preserveSymlinks, customConditions) {
    return (compilerOptions) => {
        // target of 9 is ES2022 (using the number avoids an expensive import of typescript just for an enum)
        if (compilerOptions.target === undefined || compilerOptions.target < 9 /** ES2022 */) {
            // If 'useDefineForClassFields' is already defined in the users project leave the value as is.
            // Otherwise fallback to false due to https://github.com/microsoft/TypeScript/issues/45995
            // which breaks the deprecated `@Effects` NGRX decorator and potentially other existing code as well.
            compilerOptions.target = 9 /** ES2022 */;
            compilerOptions.useDefineForClassFields ??= false;
            // Only add the warning on the initial build
            setupWarnings?.push({
                text: `TypeScript compiler options 'target' and 'useDefineForClassFields' are set to 'ES2022' and ` +
                    `'false' respectively by the Angular CLI.`,
                location: { file: pluginOptions.tsconfig },
                notes: [
                    {
                        text: 'To control ECMA version and features use the Browserslist configuration. ' +
                            'For more information, see https://angular.dev/tools/cli/build#configuring-browser-compatibility',
                    },
                ],
            });
        }
        if (compilerOptions.compilationMode === 'partial') {
            setupWarnings?.push({
                text: 'Angular partial compilation mode is not supported when building applications.',
                location: null,
                notes: [{ text: 'Full compilation mode will be used instead.' }],
            });
            compilerOptions.compilationMode = 'full';
        }
        // Enable incremental compilation by default if caching is enabled and incremental is not explicitly disabled
        if (compilerOptions.incremental !== false &&
            pluginOptions.sourceFileCache?.persistentCachePath) {
            compilerOptions.incremental = true;
            // Set the build info file location to the configured cache directory
            compilerOptions.tsBuildInfoFile = path.join(pluginOptions.sourceFileCache?.persistentCachePath, '.tsbuildinfo');
        }
        else {
            compilerOptions.incremental = false;
        }
        if (compilerOptions.module === undefined || compilerOptions.module < 5 /** ES2015 */) {
            compilerOptions.module = 7; /** ES2022 */
            setupWarnings?.push({
                text: `TypeScript compiler options 'module' values 'CommonJS', 'UMD', 'System' and 'AMD' are not supported.`,
                location: null,
                notes: [{ text: `The 'module' option will be set to 'ES2022' instead.` }],
            });
        }
        if (compilerOptions.isolatedModules && compilerOptions.emitDecoratorMetadata) {
            setupWarnings?.push({
                text: `TypeScript compiler option 'isolatedModules' may prevent the 'emitDecoratorMetadata' option from emitting all metadata.`,
                location: null,
                notes: [
                    {
                        text: `The 'emitDecoratorMetadata' option is not required by Angular` +
                            'and can be removed if not explictly required by the project.',
                    },
                ],
            });
        }
        // Synchronize custom resolve conditions.
        // Set if using the supported bundler resolution mode (bundler is the default in new projects)
        if (compilerOptions.moduleResolution === 100 /* ModuleResolutionKind.Bundler */ ||
            compilerOptions.module === 200 /** ModuleKind.Preserve */) {
            compilerOptions.customConditions = customConditions;
        }
        return {
            ...compilerOptions,
            noEmitOnError: false,
            composite: false,
            inlineSources: !!pluginOptions.sourcemap,
            inlineSourceMap: !!pluginOptions.sourcemap,
            sourceMap: undefined,
            mapRoot: undefined,
            sourceRoot: undefined,
            preserveSymlinks,
            externalRuntimeStyles: pluginOptions.externalRuntimeStyles,
            _enableHmr: !!pluginOptions.templateUpdates,
            supportTestBed: !!pluginOptions.includeTestMetadata,
            supportJitMode: !!pluginOptions.includeTestMetadata,
        };
    };
}
function bundleWebWorker(build, pluginOptions, workerFile) {
    try {
        return build.esbuild.buildSync({
            ...build.initialOptions,
            platform: 'browser',
            write: false,
            bundle: true,
            metafile: true,
            format: 'esm',
            entryNames: 'worker-[hash]',
            entryPoints: [workerFile],
            sourcemap: pluginOptions.sourcemap,
            // Zone.js is not used in Web workers so no need to disable
            supported: undefined,
            // Plugins are not supported in sync esbuild calls
            plugins: undefined,
        });
    }
    catch (error) {
        if (error && typeof error === 'object' && 'errors' in error && 'warnings' in error) {
            return error;
        }
        throw error;
    }
}
function createMissingFileError(request, original, root) {
    const relativeRequest = path.relative(root, request);
    const error = {
        text: `File '${relativeRequest}' is missing from the TypeScript compilation.`,
        notes: [
            {
                text: `Ensure the file is part of the TypeScript program via the 'files' or 'include' property.`,
            },
        ],
    };
    const relativeOriginal = path.relative(root, original);
    if (relativeRequest !== relativeOriginal) {
        error.notes.push({
            text: `File is requested from a file replacement of '${relativeOriginal}'.`,
        });
    }
    return error;
}
