var DependenciesBlockVariable = require('webpack/lib/DependenciesBlockVariable');

var pluginCompat = require('./util/plugin-compat');

const BlockSchemas3 = [
  ['AMDRequireDependenciesBlock', 'expr', 'arrayRange', 'functionRange', 'errorCallbackRange', 'module', 'loc'],
  ['ImportDependenciesBlock', 'request', 'range', 'chunkName', 'module', 'loc'],
  ['RequireEnsureDependenciesBlock', 'expr', 'successExpression', 'errorExpression', 'chunkName', 'chunkNameRange', 'module', 'loc'],
  ['AsyncDependenciesBlock', 'name', 'module'],
];

const BlockSchemas4 = [
  ['AMDRequireDependenciesBlock', 'expr', 'arrayRange', 'functionRange', 'errorCallbackRange', 'module', 'loc', 'request'],
  ['ImportDependenciesBlock', 'request', 'range', 'chunkName', 'module', 'loc', 'originModule'],
  ['RequireEnsureDependenciesBlock', 'expr', 'successExpression', 'errorExpression', 'chunkName', 'chunkNameRange', 'module', 'loc'],
  ['AsyncDependenciesBlock', 'name', 'module', 'loc', 'request'],
];

try {
  BlockSchemas3[0].DependencyBlock = require('webpack/lib/dependencies/AMDRequireDependenciesBlock');
  BlockSchemas4[0].DependencyBlock = require('webpack/lib/dependencies/AMDRequireDependenciesBlock');
} catch (_) {}
try {
  BlockSchemas3[1].DependencyBlock = require('webpack/lib/dependencies/ImportDependenciesBlock');
  BlockSchemas4[1].DependencyBlock = require('webpack/lib/dependencies/ImportDependenciesBlock');
} catch (_) {}
try {
  BlockSchemas3[2].DependencyBlock = require('webpack/lib/dependencies/RequireEnsureDependenciesBlock');
  BlockSchemas4[2].DependencyBlock = require('webpack/lib/dependencies/RequireEnsureDependenciesBlock');
} catch (_) {}
try {
  BlockSchemas3[3].DependencyBlock = require('webpack/lib/AsyncDependenciesBlock');
  BlockSchemas4[3].DependencyBlock = require('webpack/lib/AsyncDependenciesBlock');
} catch (_) {}

const freezeArgument = {
  chunkName: function(arg, block, extra, methods) {
    return block.name;
  },
  name: function(arg, block, extra, methods) {
    return block.chunkName;
  },
  module: function(arg, block, extra, methods) {},
  originModule: function(arg, block, extra, methods) {},
};

const thawArgument = {
  module: function(arg, frozen, extra, methods) {
    return extra.module;
  },
  originModule: function(arg, block, extra, methods) {
    return extra.module;
  },
};

function freezeDependencyBlock(dependencyBlock, extra, methods) {
  var schemas = extra.schemas;
  for (let i = 0; i < schemas.length; i++) {
    if (dependencyBlock.constructor === schemas[i].DependencyBlock) {
      var frozen = {
        type: schemas[i][0],
      };
      for (let j = 1; j < schemas[i].length; j++) {
        var arg = dependencyBlock[schemas[i][j]];
        if (freezeArgument[schemas[i][j]]) {
          arg = freezeArgument[schemas[i][j]](arg, dependencyBlock, extra, methods);
        }
        frozen[schemas[i][j]] = arg;
      }
      return frozen;
    }
  }
}

function thawDependencyBlock(frozen, extra, methods) {
  var schemas = extra.schemas;
  for (let i = 0; i < schemas.length; i++) {
    if (frozen.type === schemas[i][0]) {
      var DependencyBlock = schemas[i].DependencyBlock;
      var args = [];
      for (let j = 1; j < schemas[i].length; j++) {
        var arg = frozen[schemas[i][j]];
        if (thawArgument[schemas[i][j]]) {
          arg = thawArgument[schemas[i][j]](arg, frozen, extra, methods);
        }
        args.push(arg);
      }
      try {
        return new DependencyBlock(...args);
      } catch (_) {
        return new (Function.prototype.bind.apply(DependencyBlock, [null].concat(args)))();
      }
    }
  }
}

function HardDependencyBlockPlugin(options) {
  this.options = options;
}

HardDependencyBlockPlugin.prototype.apply = function(compiler) {
  let schemas = BlockSchemas4;
  if (this.options.schema < 4) {
    schemas = BlockSchemas3;
  }

  var methods;

  pluginCompat.tap(compiler, '_hardSourceMethods', 'HardDependencyBlockPlugin', function(_methods) {
    methods = _methods;
  });

  var mapFreeze, mapThaw;

  pluginCompat.tap(compiler, '_hardSourceMethods', 'HardDependencyBlockPlugin', function(methods) {
    // store = methods.store;
    // fetch = methods.fetch;
    // freeze = methods.freeze;
    // thaw = methods.thaw;
    mapFreeze = methods.mapFreeze;
    mapThaw = methods.mapThaw;
  });

  pluginCompat.tap(compiler, '_hardSourceFreezeDependencyVariable', 'HardDependencyBlockPlugin', function(frozen, variable, extra) {
    return {
      type: 'DependenciesBlockVariable',
      name: variable.name,
      expression: variable.expression,
      dependencies: mapFreeze('Dependency', null, variable.dependencies, extra),
    };
  });

  pluginCompat.tap(compiler, '_hardSourceFreezeDependencyBlock', 'HardDependencyBlockPlugin', function(frozen, block, extra) {
    extra.schemas = schemas;
    const _frozen = freezeDependencyBlock(block, extra, methods);
    if (_frozen) {
      if (
        block.dependencies &&
        block.dependencies.length > 0 ||
        block.variables &&
        block.variables.length > 0 ||
        block.blocks &&
        block.blocks.length > 0
      ) {
        _frozen.dependencies = mapFreeze('Dependency', null, block.dependencies, extra);
        _frozen.variables = mapFreeze('DependencyVariable', null, block.variables, extra);
        _frozen.blocks = mapFreeze('DependencyBlock', null, block.blocks, extra);
      }
      if (block.parent) {
        _frozen.parent = true;
      }
      return _frozen;
    }

    return {
      type: 'DependenciesBlock',
      dependencies: mapFreeze('Dependency', null, block.dependencies, extra),
      variables: mapFreeze('DependencyVariable', null, block.variables, extra),
      blocks: mapFreeze('DependencyBlock', null, block.blocks, extra),
    };
  });

  pluginCompat.tap(compiler, '_hardSourceThawDependencyVariable', 'HardDependencyBlockPlugin', function(variable, frozen, extra) {
    return new DependenciesBlockVariable(
      frozen.name,
      frozen.expression,
      mapThaw('Dependency', null, frozen.dependencies, extra)
    );
  });

  pluginCompat.tap(compiler, '_hardSourceThawDependencyBlock', 'HardDependencyBlockPlugin', function(block, frozen, extra) {
    extra.schemas = schemas;
    const _thawed = thawDependencyBlock(frozen, extra, methods);
    if (_thawed) {
      if (_thawed.dependencies) {
        var blockExtra = {
          state: extra.state,
          module: extra.module,
          parent: _thawed,
          compilation: extra.compilation,
        };
        _thawed.dependencies = mapThaw('Dependency', null, frozen.dependencies, blockExtra);
        _thawed.variables = mapThaw('DependencyVariable', null, frozen.variables, blockExtra);
        mapThaw('DependencyBlock', null, frozen.blocks, blockExtra);
      }
      if (frozen.parent) {
        extra.parent.addBlock(_thawed);
      }
      return _thawed;
    }

    if (block) {
      var blockExtra = {
        state: extra.state,
        module: extra.module,
        parent: block,
        compilation: extra.compilation,
      };
      block.dependencies = mapThaw('Dependency', null, frozen.dependencies, blockExtra);
      block.variables = mapThaw('DependencyVariable', null, frozen.variables, blockExtra);
      block.blocks = mapThaw('DependencyBlock', null, frozen.blocks, blockExtra);
    }

    return block;
  });
};

module.exports = HardDependencyBlockPlugin;

@@ -1939,17 +1939,22 @@
 n block.
-n
+chunkN
 ame;%0A  %7D
@@ -2011,38 +2011,33 @@
    return block.
-chunkN
+n
 ame;%0A  %7D,%0A  modu

Fix chunkName freezing in hard-source-block-plugin.