text: // This file is auto-generated from the corresponding file in /dev_mode
  // This file is auto-generated from the corresponding file in /dev_mode
  /* -----------------------------------------------------------------------------
  | Copyright (c) Jupyter Development Team.
  | Distributed under the terms of the Modified BSD License.
  |----------------------------------------------------------------------------*/
  
  const path = require('path');
  const fs = require('fs-extra');
  const Handlebars = require('handlebars');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const webpack = require('webpack');
  const merge = require('webpack-merge').default;
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
    .BundleAnalyzerPlugin;
  const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base');
  const { ModuleFederationPlugin } = webpack.container;
  
  const Build = require('@jupyterlab/builder').Build;
  const WPPlugin = require('@jupyterlab/builder').WPPlugin;
  const packageData = require('./package.json');
  
  // Handle the extensions.
  const jlab = packageData.jupyterlab;
  const { extensions, mimeExtensions, externalExtensions } = jlab;
  
  // Add external extensions to the extensions/mimeExtensions data as
  // appropriate
  for (const pkg in externalExtensions) {
    const {
      jupyterlab: { extension, mimeExtension }
    } = require(`${pkg}/package.json`);
    if (extension !== undefined) {
      extensions[pkg] = extension === true ? '' : extension;
    }
    if (mimeExtension !== undefined) {
      mimeExtensions[pkg] = mimeExtension === true ? '' : mimeExtension;
    }
  }
  
  // Deduplicated list of extension package names.
  const extensionPackages = [
    ...new Set([...Object.keys(extensions), ...Object.keys(mimeExtensions)])
  ];
  
  // Ensure a clear build directory.
  const buildDir = path.resolve(jlab.buildDir);
  if (fs.existsSync(buildDir)) {
    fs.removeSync(buildDir);
  }
  fs.ensureDirSync(buildDir);
  
  const outputDir = path.resolve(jlab.outputDir);
  
  // Configuration to handle extension assets
  const extensionAssetConfig = Build.ensureAssets({
    packageNames: extensionPackages,
    output: outputDir
  });
  
  // Create the entry point and other assets in build directory.
  const source = fs.readFileSync('index.js').toString();
  const template = Handlebars.compile(source);
  const extData = {
    jupyterlab_extensions: extensions,
    jupyterlab_mime_extensions: mimeExtensions
  };
  fs.writeFileSync(path.join(buildDir, 'index.out.js'), template(extData));
  
  // Create the bootstrap file that loads federated extensions and calls the
  // initialization logic in index.out.js
  const entryPoint = path.join(buildDir, 'bootstrap.js');
  fs.copySync('./bootstrap.js', entryPoint);
  
  fs.copySync('./package.json', path.join(buildDir, 'package.json'));
  if (outputDir !== buildDir) {
    fs.copySync(
      path.join(outputDir, 'style.js'),
      path.join(buildDir, 'style.js')
    );
  }
  
  // Set up variables for the watch mode ignore plugins
  const watched = {};
  const ignoreCache = Object.create(null);
  let watchNodeModules = false;
  Object.keys(jlab.linkedPackages).forEach(function (name) {
    if (name in watched) {
      return;
    }
    let localPkgPath = '';
    try {
      localPkgPath = require.resolve(path.join(name, 'package.json'));
    } catch (e) {
      return;
    }
    watched[name] = path.dirname(localPkgPath);
    if (localPkgPath.indexOf('node_modules') !== -1) {
      watchNodeModules = true;
    }
  });
  
  // Set up source-map-loader to look in watched lib dirs
  const sourceMapRes = Object.values(watched).reduce((res, name) => {
    res.push(new RegExp(name + '/lib'));
    return res;
  }, []);
  
  /**
   * Sync a local path to a linked package path if they are files and differ.
   * This is used by `jupyter lab --watch` to synchronize linked packages
   * and has no effect in `jupyter lab --dev-mode --watch`.
   */
  function maybeSync(localPath, name, rest) {
    let stats;
    try {
      stats = fs.statSync(localPath);
    } catch (e) {
      return;
    }
  
    if (!stats.isFile(localPath)) {
      return;
    }
    const source = fs.realpathSync(path.join(jlab.linkedPackages[name], rest));
    if (source === fs.realpathSync(localPath)) {
      return;
    }
    fs.watchFile(source, { interval: 500 }, function (curr) {
      if (!curr || curr.nlink === 0) {
        return;
      }
      try {
        fs.copySync(source, localPath);
      } catch (err) {
        console.error(err);
      }
    });
  }
  
  /**
   * A filter function set up to exclude all files that are not
   * in a package contained by the Jupyterlab repo. Used to ignore
   * files during a `--watch` build.
   */
  function ignored(checkedPath) {
    checkedPath = path.resolve(checkedPath);
    if (checkedPath in ignoreCache) {
      // Bail if already found.
      return ignoreCache[checkedPath];
    }
  
    // Limit the watched files to those in our local linked package dirs.
    let ignore = true;
    Object.keys(watched).some(name => {
      const rootPath = watched[name];
      const contained = checkedPath.indexOf(rootPath + path.sep) !== -1;
      if (checkedPath !== rootPath && !contained) {
        return false;
      }
      const rest = checkedPath.slice(rootPath.length);
      if (rest.indexOf('node_modules') === -1) {
        ignore = false;
        maybeSync(checkedPath, name, rest);
      }
      return true;
    });
    ignoreCache[checkedPath] = ignore;
    return ignore;
  }
  
  // Set up module federation sharing config
  const shared = {};
  
  // Make sure any resolutions are shared
  for (let [pkg, requiredVersion] of Object.entries(packageData.resolutions)) {
    shared[pkg] = { requiredVersion };
  }
  
  // Add any extension packages that are not in resolutions (i.e., installed from npm)
  for (let pkg of extensionPackages) {
    if (!shared[pkg]) {
      shared[pkg] = {
        requiredVersion: require(`${pkg}/package.json`).version
      };
    }
  }
  
  // Add dependencies and sharedPackage config from extension packages if they
  // are not already in the shared config. This means that if there is a
  // conflict, the resolutions package version is the one that is shared.
  const extraShared = [];
  for (let pkg of extensionPackages) {
    let pkgShared = {};
    let {
      dependencies = {},
      jupyterlab: { sharedPackages = {} } = {}
    } = require(`${pkg}/package.json`);
    for (let [dep, requiredVersion] of Object.entries(dependencies)) {
      if (!shared[dep]) {
        pkgShared[dep] = { requiredVersion };
      }
    }
  
    // Overwrite automatic dependency sharing with custom sharing config
    for (let [dep, config] of Object.entries(sharedPackages)) {
      if (config === false) {
        delete pkgShared[dep];
      } else {
        if ('bundled' in config) {
          config.import = config.bundled;
          delete config.bundled;
        }
        pkgShared[dep] = config;
      }
    }
    extraShared.push(pkgShared);
  }
  
  // Now merge the extra shared config
  const mergedShare = {};
  for (let sharedConfig of extraShared) {
    for (let [pkg, config] of Object.entries(sharedConfig)) {
      // Do not override the basic share config from resolutions
      if (shared[pkg]) {
        continue;
      }
  
      // Add if we haven't seen the config before
      if (!mergedShare[pkg]) {
        mergedShare[pkg] = config;
        continue;
      }
  
      // Choose between the existing config and this new config. We do not try
      // to merge configs, which may yield a config no one wants
      let oldConfig = mergedShare[pkg];
  
      // if the old one has import: false, use the new one
      if (oldConfig.import === false) {
        mergedShare[pkg] = config;
      }
    }
  }
  
  Object.assign(shared, mergedShare);
  
  // Transform any file:// requiredVersion to the version number from the
  // imported package. This assumes (for simplicity) that the version we get
  // importing was installed from the file.
  for (let [pkg, { requiredVersion }] of Object.entries(shared)) {
    if (requiredVersion && requiredVersion.startsWith('file:')) {
      shared[pkg].requiredVersion = require(`${pkg}/package.json`).version;
    }
  }
  
  // Add singleton package information
  for (let pkg of jlab.singletonPackages) {
    shared[pkg].singleton = true;
  }
  
  const plugins = [
    new WPPlugin.NowatchDuplicatePackageCheckerPlugin({
      verbose: true,
      exclude(instance) {
        // ignore known duplicates
        return ['domelementtype', 'hash-base', 'inherits'].includes(
          instance.name
        );
      }
    }),
    new HtmlWebpackPlugin({
      chunksSortMode: 'none',
      template: path.join(__dirname, 'templates', 'template.html'),
      title: jlab.name || 'JupyterLab'
    }),
    // custom plugin for ignoring files during a `--watch` build
    new WPPlugin.FilterWatchIgnorePlugin(ignored),
    // custom plugin that copies the assets to the static directory
    new WPPlugin.FrontEndPlugin(buildDir, jlab.staticDir),
    new ModuleFederationPlugin({
      library: {
        type: 'var',
        name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION']
      },
      name: 'CORE_FEDERATION',
      shared
    })
  ];
  
  if (process.argv.includes('--analyze')) {
    plugins.push(new BundleAnalyzerPlugin());
  }
  
  module.exports = [
    merge(baseConfig, {
      mode: 'development',
      entry: {
        main: ['./publicpath', 'whatwg-fetch', entryPoint]
      },
      output: {
        path: path.resolve(buildDir),
        publicPath: '{{page_config.fullStaticUrl}}/',
        filename: '[name].[contenthash].js'
      },
      optimization: {
        splitChunks: {
          chunks: 'all',
          cacheGroups: {
            jlab_core: {
              test: /[\\/]node_modules[\\/]@(jupyterlab|lumino)[\\/]/,
              name: 'jlab_core'
            }
          }
        }
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            include: sourceMapRes,
            use: ['source-map-loader'],
            enforce: 'pre'
          }
        ]
      },
      devtool: 'inline-source-map',
      externals: ['node-fetch', 'ws'],
      plugins
    })
  ].concat(extensionAssetConfig);
  
  // Needed to watch changes in linked extensions in node_modules
  // (jupyter lab --watch)
  // See https://github.com/webpack/webpack/issues/11612
  if (watchNodeModules) {
    module.exports[0].snapshot = { managedPaths: [] };
  }
  
  const logPath = path.join(buildDir, 'build_log.json');
  fs.writeFileSync(logPath, JSON.stringify(module.exports, null, '  '));
  