text: // @flow
  import type {Config, FilePath, PluginOptions} from '@parcel/types';
  import type {PluginLogger} from '@parcel/logger';
  import path from 'path';
  import {relativePath} from '@parcel/utils';
  import nullthrows from 'nullthrows';
  
  import loadExternalPlugins from './loadPlugins';
  
  const MODULE_BY_NAME_RE = /\.module\./;
  
  async function configHydrator(
    configFile: any,
    config: Config,
    resolveFrom: ?FilePath,
    options: PluginOptions,
  ) {
    // Use a basic, modules-only PostCSS config if the file opts in by a name
    // like foo.module.css
    if (configFile == null && config.searchPath.match(MODULE_BY_NAME_RE)) {
      configFile = {
        plugins: {
          'postcss-modules': {},
        },
      };
      resolveFrom = __filename;
    }
  
    if (configFile == null) {
      return;
    }
  
    // Load the custom config...
    let modulesConfig;
    let configFilePlugins = configFile.plugins;
    if (
      configFilePlugins != null &&
      typeof configFilePlugins === 'object' &&
      configFilePlugins['postcss-modules'] != null
    ) {
      modulesConfig = configFilePlugins['postcss-modules'];
      delete configFilePlugins['postcss-modules'];
    }
  
    if (!modulesConfig && configFile.modules) {
      modulesConfig = {};
    }
  
    let plugins = await loadExternalPlugins(
      configFilePlugins,
      nullthrows(resolveFrom),
      options,
    );
  
    // contents is either:
    // from JSON:    { plugins: { 'postcss-foo': { ...opts } } }
    // from JS (v8): { plugins: [ { postcssPlugin: 'postcss-foo', ...visitor callback functions } ]
    // from JS (v7): { plugins: [ [Function: ...] ]
    let pluginArray = Array.isArray(configFilePlugins)
      ? configFilePlugins
      : Object.keys(configFilePlugins);
    for (let p of pluginArray) {
      if (typeof p === 'string') {
        config.addDevDependency({
          moduleSpecifier: p,
          resolveFrom: nullthrows(resolveFrom),
        });
      }
    }
  
    config.setResult({
      raw: configFile,
      hydrated: {
        plugins,
        from: config.searchPath,
        to: config.searchPath,
        modules: modulesConfig,
      },
    });
  }
  
  export async function load({
    config,
    options,
    logger,
  }: {|
    config: Config,
    options: PluginOptions,
    logger: PluginLogger,
  |}): Promise<void> {
    let configFile: any = await config.getConfig(
      ['.postcssrc', '.postcssrc.json', '.postcssrc.js', 'postcss.config.js'],
      {packageKey: 'postcss'},
    );
  
    let contents = null;
    if (configFile) {
      contents = configFile.contents;
      let isDynamic = configFile && path.extname(configFile.filePath) === '.js';
      if (isDynamic) {
        // We have to invalidate on startup in case the config is non-deterministic,
        // e.g. using unknown environment variables, reading from the filesystem, etc.
        logger.warn({
          message:
            'WARNING: Using a JavaScript PostCSS config file means losing out on caching features of Parcel. Use a .postcssrc(.json) file whenever possible.',
        });
  
        config.shouldInvalidateOnStartup();
  
        // Also add the config as a dev dependency so we attempt to reload in watch mode.
        config.addDevDependency({
          moduleSpecifier: relativePath(
            path.dirname(config.searchPath),
            configFile.filePath,
          ),
          resolveFrom: config.searchPath,
        });
      }
  
      if (typeof contents !== 'object') {
        throw new Error('PostCSS config should be an object.');
      }
  
      if (
        contents.plugins == null ||
        typeof contents.plugins !== 'object' ||
        Object.keys(contents.plugins).length === 0
      ) {
        throw new Error('PostCSS config must have plugins');
      }
    }
  
    return configHydrator(contents, config, configFile?.filePath, options);
  }
  