/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */ "use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "ClientReferenceManifestPlugin", {
    enumerable: true,
    get: function() {
        return ClientReferenceManifestPlugin;
    }
});
const _path = /*#__PURE__*/ _interop_require_wildcard(require("path"));
const _webpack = require("next/dist/compiled/webpack/webpack");
const _constants = require("../../../shared/lib/constants");
const _utils = require("../loaders/utils");
const _buildcontext = require("../../build-context");
const _utils1 = require("../utils");
const _nonnullable = require("../../../lib/non-nullable");
const _constants1 = require("../../../lib/constants");
const _clientreference = require("../../../lib/client-reference");
function _getRequireWildcardCache(nodeInterop) {
    if (typeof WeakMap !== "function") return null;
    var cacheBabelInterop = new WeakMap();
    var cacheNodeInterop = new WeakMap();
    return (_getRequireWildcardCache = function(nodeInterop) {
        return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
    })(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
    if (!nodeInterop && obj && obj.__esModule) {
        return obj;
    }
    if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
        return {
            default: obj
        };
    }
    var cache = _getRequireWildcardCache(nodeInterop);
    if (cache && cache.has(obj)) {
        return cache.get(obj);
    }
    var newObj = {};
    var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
    for(var key in obj){
        if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
            var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
            if (desc && (desc.get || desc.set)) {
                Object.defineProperty(newObj, key, desc);
            } else {
                newObj[key] = obj[key];
            }
        }
    }
    newObj.default = obj;
    if (cache) {
        cache.set(obj, newObj);
    }
    return newObj;
}
const pluginState = (0, _buildcontext.getProxiedPluginState)({
    serverModuleIds: {},
    edgeServerModuleIds: {},
    ASYNC_CLIENT_MODULES: []
});
const PLUGIN_NAME = "ClientReferenceManifestPlugin";
class ClientReferenceManifestPlugin {
    constructor(options){
        this.dev = false;
        this.dev = options.dev;
        this.appDir = options.appDir;
        this.ASYNC_CLIENT_MODULES = new Set(pluginState.ASYNC_CLIENT_MODULES);
    }
    apply(compiler) {
        compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory  })=>{
            compilation.dependencyFactories.set(_webpack.webpack.dependencies.ModuleDependency, normalModuleFactory);
            compilation.dependencyTemplates.set(_webpack.webpack.dependencies.ModuleDependency, new _webpack.webpack.dependencies.NullDependency.Template());
        });
        compiler.hooks.make.tap(PLUGIN_NAME, (compilation)=>{
            compilation.hooks.processAssets.tap({
                name: PLUGIN_NAME,
                // Have to be in the optimize stage to run after updating the CSS
                // asset hash via extract mini css plugin.
                stage: _webpack.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH
            }, (assets)=>this.createAsset(assets, compilation, compiler.context));
        });
    }
    createAsset(assets, compilation, context) {
        const manifest = {
            ssrModuleMapping: {},
            edgeSSRModuleMapping: {},
            clientModules: {}
        };
        const clientRequestsSet = new Set();
        // Collect client requests
        function collectClientRequest(mod) {
            if (mod.resource === "" && mod.buildInfo.rsc) {
                const { requests =[]  } = mod.buildInfo.rsc;
                requests.forEach((r)=>{
                    clientRequestsSet.add(r);
                });
            }
        }
        (0, _utils1.traverseModules)(compilation, (mod)=>collectClientRequest(mod));
        compilation.chunkGroups.forEach((chunkGroup)=>{
            const recordModule = (id, mod, chunkCSS)=>{
                var _mod_resourceResolveData, _mod_buildInfo_rsc;
                const isCSSModule = (0, _utils.isCSSMod)(mod);
                // Skip all modules from the pages folder. CSS modules are a special case
                // as they are generated by mini-css-extract-plugin and these modules
                // don't have layer information attached.
                if (!isCSSModule && mod.layer !== _constants1.WEBPACK_LAYERS.appClient) {
                    return;
                }
                const resource = mod.type === "css/mini-extract" ? mod._identifier.slice(mod._identifier.lastIndexOf("!") + 1) : mod.resource;
                if (!resource) {
                    return;
                }
                const moduleReferences = manifest.clientModules;
                const moduleIdMapping = manifest.ssrModuleMapping;
                const edgeModuleIdMapping = manifest.edgeSSRModuleMapping;
                // Note that this isn't that reliable as webpack is still possible to assign
                // additional queries to make sure there's no conflict even using the `named`
                // module ID strategy.
                let ssrNamedModuleId = (0, _path.relative)(context, ((_mod_resourceResolveData = mod.resourceResolveData) == null ? void 0 : _mod_resourceResolveData.path) || resource);
                if (!ssrNamedModuleId.startsWith(".")) ssrNamedModuleId = `./${ssrNamedModuleId.replace(/\\/g, "/")}`;
                if (isCSSModule) {
                    const exportName = (0, _clientreference.getClientReferenceModuleKey)(resource, "");
                    if (!moduleReferences[exportName]) {
                        moduleReferences[exportName] = {
                            id: id || "",
                            name: "default",
                            chunks: chunkCSS
                        };
                    } else {
                        // It is possible that there are multiple modules with the same resource,
                        // e.g. extracted by mini-css-extract-plugin. In that case we need to
                        // merge the chunks.
                        moduleReferences[exportName].chunks = [
                            ...new Set([
                                ...moduleReferences[exportName].chunks,
                                ...chunkCSS
                            ])
                        ];
                    }
                    return;
                }
                // Only apply following logic to client module requests from client entry,
                // or if the module is marked as client module.
                if (!clientRequestsSet.has(resource) && !(0, _utils.isClientComponentEntryModule)(mod)) {
                    return;
                }
                const exportsInfo = compilation.moduleGraph.getExportsInfo(mod);
                const isAsyncModule = this.ASYNC_CLIENT_MODULES.has(mod.resource);
                const cjsExports = [
                    ...new Set([
                        ...mod.dependencies.map((dep)=>{
                            // Match CommonJsSelfReferenceDependency
                            if (dep.type === "cjs self exports reference") {
                                // @ts-expect-error: TODO: Fix Dependency type
                                if (dep.base === "module.exports") {
                                    return "default";
                                }
                                // `exports.foo = ...`, `exports.default = ...`
                                // @ts-expect-error: TODO: Fix Dependency type
                                if (dep.base === "exports") {
                                    // @ts-expect-error: TODO: Fix Dependency type
                                    return dep.names.filter((name)=>name !== "__esModule");
                                }
                            }
                            return null;
                        }),
                        ...((_mod_buildInfo_rsc = mod.buildInfo.rsc) == null ? void 0 : _mod_buildInfo_rsc.clientRefs) || []
                    ].filter(Boolean).flat())
                ];
                function getAppPathRequiredChunks() {
                    return chunkGroup.chunks.map((requiredChunk)=>{
                        if (_constants.SYSTEM_ENTRYPOINTS.has(requiredChunk.name)) {
                            return null;
                        }
                        // Get the actual chunk file names from the chunk file list.
                        // It's possible that the chunk is generated via `import()`, in
                        // that case the chunk file name will be '[name].[contenthash]'
                        // instead of '[name]-[chunkhash]'.
                        return [
                            ...requiredChunk.files
                        ].map((file)=>{
                            // It's possible that a chunk also emits CSS files, that will
                            // be handled separatedly.
                            if (!file.endsWith(".js")) return null;
                            if (file.endsWith(".hot-update.js")) return null;
                            return requiredChunk.id + ":" + file;
                        });
                    }).flat().filter(_nonnullable.nonNullable);
                }
                const requiredChunks = getAppPathRequiredChunks();
                // The client compiler will always use the CJS Next.js build, so here we
                // also add the mapping for the ESM build (Edge runtime) to consume.
                const esmResource = /[\\/]next[\\/]dist[\\/]/.test(resource) ? resource.replace(/[\\/]next[\\/]dist[\\/]/, "/next/dist/esm/".replace(/\//g, _path.default.sep)) : null;
                function addClientReference(name) {
                    const exportName = (0, _clientreference.getClientReferenceModuleKey)(resource, name);
                    manifest.clientModules[exportName] = {
                        id,
                        name,
                        chunks: requiredChunks,
                        async: isAsyncModule
                    };
                    if (esmResource) {
                        const edgeExportName = (0, _clientreference.getClientReferenceModuleKey)(esmResource, name);
                        manifest.clientModules[edgeExportName] = manifest.clientModules[exportName];
                    }
                }
                function addSSRIdMapping(name) {
                    const exportName = (0, _clientreference.getClientReferenceModuleKey)(resource, name);
                    if (typeof pluginState.serverModuleIds[ssrNamedModuleId] !== "undefined") {
                        moduleIdMapping[id] = moduleIdMapping[id] || {};
                        moduleIdMapping[id][name] = {
                            ...manifest.clientModules[exportName],
                            id: pluginState.serverModuleIds[ssrNamedModuleId]
                        };
                    }
                    if (typeof pluginState.edgeServerModuleIds[ssrNamedModuleId] !== "undefined") {
                        edgeModuleIdMapping[id] = edgeModuleIdMapping[id] || {};
                        edgeModuleIdMapping[id][name] = {
                            ...manifest.clientModules[exportName],
                            id: pluginState.edgeServerModuleIds[ssrNamedModuleId]
                        };
                    }
                }
                addClientReference("*");
                addClientReference("");
                addSSRIdMapping("*");
                addSSRIdMapping("");
                const moduleExportedKeys = [
                    ...[
                        ...exportsInfo.exports
                    ].filter((exportInfo)=>exportInfo.provided).map((exportInfo)=>exportInfo.name),
                    ...cjsExports
                ].filter((name)=>name !== null);
                moduleExportedKeys.forEach((name)=>{
                    const key = (0, _clientreference.getClientReferenceModuleKey)(resource, name);
                    // If the chunk is from `app/` chunkGroup, use it first.
                    // This make sure not to load the overlapped chunk from `pages/` chunkGroup
                    if (!manifest.clientModules[key] || chunkGroup.name && /^app[\\/]/.test(chunkGroup.name)) {
                        addClientReference(name);
                    }
                    addSSRIdMapping(name);
                });
                manifest.clientModules = moduleReferences;
                manifest.ssrModuleMapping = moduleIdMapping;
                manifest.edgeSSRModuleMapping = edgeModuleIdMapping;
            };
            chunkGroup.chunks.forEach((chunk)=>{
                const chunkModules = compilation.chunkGraph.getChunkModulesIterable(chunk);
                const chunkCSS = [
                    ...chunk.files
                ].filter((f)=>!f.startsWith("static/css/pages/") && f.endsWith(".css"));
                for (const mod of chunkModules){
                    const modId = compilation.chunkGraph.getModuleId(mod) + "";
                    recordModule(modId, mod, chunkCSS);
                    // If this is a concatenation, register each child to the parent ID.
                    // TODO: remove any
                    const anyModule = mod;
                    if (anyModule.modules) {
                        anyModule.modules.forEach((concatenatedMod)=>{
                            recordModule(modId, concatenatedMod, chunkCSS);
                        });
                    }
                }
            });
        });
        const file = "server/" + _constants.CLIENT_REFERENCE_MANIFEST;
        const json = JSON.stringify(manifest, null, this.dev ? 2 : undefined);
        pluginState.ASYNC_CLIENT_MODULES = [];
        assets[file + ".js"] = new _webpack.sources.RawSource("self.__RSC_MANIFEST=" + json);
        assets[file + ".json"] = new _webpack.sources.RawSource(json);
    }
}

//# sourceMappingURL=flight-manifest-plugin.js.map