"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 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.setupJitPluginCallbacks = setupJitPluginCallbacks; const promises_1 = require("node:fs/promises"); const node_path_1 = require("node:path"); const uri_1 = require("../../angular/uri"); const load_result_cache_1 = require("../load-result-cache"); /** * Loads/extracts the contents from a load callback Angular JIT entry. * An Angular JIT entry represents either a file path for a component resource or base64 * encoded data for an inline component resource. * @param entry The value that represents content to load. * @param root The absolute path for the root of the build (typically the workspace root). * @param skipRead If true, do not attempt to read the file; if false, read file content from disk. * This option has no effect if the entry does not originate from a file. Defaults to false. * @returns An object containing the absolute path of the contents and optionally the actual contents. * For inline entries the contents will always be provided. */ async function loadEntry(entry, root, skipRead) { if (entry.startsWith('inline:')) { const [importer, data] = entry.slice(7).split(';', 2); return { path: (0, node_path_1.join)(root, importer), contents: Buffer.from(data, 'base64').toString(), }; } const path = (0, node_path_1.join)(root, entry); return { path, contents: skipRead ? undefined : await (0, promises_1.readFile)(path, 'utf-8'), }; } /** * Sets up esbuild resolve and load callbacks to support Angular JIT mode processing * for both Component stylesheets and templates. These callbacks work alongside the JIT * resource TypeScript transformer to convert and then bundle Component resources as * static imports. * @param build An esbuild {@link PluginBuild} instance used to add callbacks. * @param styleOptions The options to use when bundling stylesheets. * @param additionalResultFiles A Map where stylesheet resources will be added. */ function setupJitPluginCallbacks(build, stylesheetBundler, additionalResultFiles, loadCache) { const root = build.initialOptions.absWorkingDir ?? ''; // Add a resolve callback to capture and parse any JIT URIs that were added by the // JIT resource TypeScript transformer. // Resources originating from a file are resolved as relative from the containing file (importer). build.onResolve({ filter: uri_1.JIT_NAMESPACE_REGEXP }, (args) => { const parsed = (0, uri_1.parseJitUri)(args.path); if (!parsed) { return undefined; } const { namespace, origin, specifier } = parsed; if (origin === 'file') { return { // Use a relative path to prevent fully resolved paths in the metafile (JSON stats file). // This is only necessary for custom namespaces. esbuild will handle the file namespace. path: (0, node_path_1.relative)(root, (0, node_path_1.join)((0, node_path_1.dirname)(args.importer), specifier)), namespace, }; } else { // Inline data may need the importer to resolve imports/references within the content const importer = (0, node_path_1.relative)(root, args.importer); return { path: `inline:${importer};${specifier}`, namespace, }; } }); // Add a load callback to handle Component stylesheets (both inline and external) build.onLoad({ filter: /./, namespace: uri_1.JIT_STYLE_NAMESPACE }, (0, load_result_cache_1.createCachedLoad)(loadCache, async (args) => { // skipRead is used here because the stylesheet bundling will read a file stylesheet // directly either via a preprocessor or esbuild itself. const entry = await loadEntry(args.path, root, true /* skipRead */); let stylesheetResult; // Stylesheet contents only exist for internal stylesheets if (entry.contents === undefined) { stylesheetResult = await stylesheetBundler.bundleFile(entry.path); } else { stylesheetResult = await stylesheetBundler.bundleInline(entry.contents, entry.path); } const { errors, warnings, referencedFiles } = stylesheetResult; if (stylesheetResult.errors) { return { errors, warnings, watchFiles: referencedFiles && [...referencedFiles], }; } const { contents, outputFiles, metafile } = stylesheetResult; additionalResultFiles.set(entry.path, { outputFiles, metafile }); return { errors, warnings, contents, loader: 'text', watchFiles: referencedFiles && [...referencedFiles], }; })); // Add a load callback to handle Component templates // NOTE: While this callback supports both inline and external templates, the transformer // currently only supports generating URIs for external templates. build.onLoad({ filter: /./, namespace: uri_1.JIT_TEMPLATE_NAMESPACE }, (0, load_result_cache_1.createCachedLoad)(loadCache, async (args) => { const { contents, path } = await loadEntry(args.path, root); return { contents, loader: 'text', watchFiles: [path], }; })); }