function match(test, options, configSetters) {
  if (!configSetters && Array.isArray(options)) {
    configSetters = options
    options = {}
  }

  assertConfigSetters(configSetters)

  if (options.test) {
    throw new Error(
      `match(): Setting 'test' in options is not supported; use the argument instead.`
    )
  }

  const { inclusions, exclusions } = splitPatterns(toArray(test))
  const match = Object.assign({}, options, {
    // The `.test` is usually just one pattern, so stripping the array feels more natural
    test: stripArrayConditionally(normalizeMatchers(inclusions))
  })

  if (exclusions.length > 0) {
    match.exclude = _.concat(
      match.exclude ? toArray(match.exclude) : [],
      normalizeMatchers(exclusions)
    )
  }

  const groupBlock = context => config =>
    invokeConfigSetters(configSetters, deriveContextWithMatch(context, match), config)

  return Object.assign(groupBlock, {
    pre: context => invokePreHooks(configSetters, deriveContextWithMatch(context, match)),
    post: context => config =>
      invokePostHooks(configSetters, deriveContextWithMatch(context, match), config)
  })
}
State on which files to apply the loader blocks passed in this call. Works
like `group()`, but adds the file matching information to the context.

@param {string|RegExp|Function|Array} test   A glob like `*.css` or `{*.js, *.jsx}` or something else to use as `loader.test`.
@param {object} [options]                    Rule options. See https://webpack.js.org/configuration/module/
@param {Function[]} configSetters            Array of functions as returned by webpack blocks.
@return {Function}