<commit_before>import path from 'path';
import CommonBugsnagPlugin from './helpers/CommonBugsnagPlugin';
import { upload } from 'bugsnag-sourcemaps';

class BugsnagSourceMapPlugin extends CommonBugsnagPlugin {
  constructor({
    apiKey = null,
    publicPath = null,
    appVersion = null,
    overwrite = false,
    endpoint = 'https://upload.bugsnag.com',
  }) {
    super();
    this.options = {
      apiKey,
      publicPath,
      appVersion,
      overwrite,
      endpoint,
    };
    this.validateOptions();
  }

  apply(compiler) {
    compiler.plugin('after-emit', this.handle.bind(this));
  }

  getSourceMaps(compilation) {
    const sourceMaps = [];

    const stats = compilation.getStats().toJson();
    const outputPath = path.resolve(
      compilation.compiler.options.context,
      compilation.compiler.options.output.path
    );
    let publicPath = this.options.publicPath || stats.publicPath;
    publicPath += /\/$/.test(publicPath) ? '' : '/';

    stats.chunks.forEach(chunk => {
      const [ file ] = chunk.files.filter(file => /\.js$/.test(file));
      const [ sourceMap ] = chunk.files.filter(file => /\.js\.map$/.test(file));

      if (sourceMap) {
        sourceMaps.push({
          url: publicPath + file,
          file: path.resolve(outputPath, file),
          sourceMap: path.resolve(outputPath, sourceMap),
        });
      }
    });

    return sourceMaps;
  }
<commit_msg>Adds support for query strings in output filenames<commit_after>import path from 'path';
import CommonBugsnagPlugin from './helpers/CommonBugsnagPlugin';
import { upload } from 'bugsnag-sourcemaps';

class BugsnagSourceMapPlugin extends CommonBugsnagPlugin {
  constructor({
    apiKey = null,
    publicPath = null,
    appVersion = null,
    overwrite = false,
    endpoint = 'https://upload.bugsnag.com',
  }) {
    super();
    this.options = {
      apiKey,
      publicPath,
      appVersion,
      overwrite,
      endpoint,
    };
    this.validateOptions();
  }

  apply(compiler) {
    compiler.plugin('after-emit', this.handle.bind(this));
  }

  getSourceMaps(compilation) {
    const sourceMaps = [];

    const stats = compilation.getStats().toJson();
    const outputPath = path.resolve(
      compilation.compiler.options.context,
      compilation.compiler.options.output.path
    );
    let publicPath = this.options.publicPath || stats.publicPath;
    publicPath += /\/$/.test(publicPath) ? '' : '/';

    stats.chunks.forEach(chunk => {

      const filesWithoutQuery = chunk.files.map(file => this.removeQueryString(file));
      const [ file ] = filesWithoutQuery.filter(file => /\.js$/.test(file));
      const [ sourceMap ] = filesWithoutQuery.filter(file => /\.js\.map$/.test(file));

      if (sourceMap) {
        sourceMaps.push({
          url: publicPath + file,
          file: path.resolve(outputPath, file),
          sourceMap: path.resolve(outputPath, sourceMap),
        });
      }
    });

    return sourceMaps;
  }

  removeQueryString (fileName) {
    // Part of the challenge here is that '?' is a valid character in
    // unix file systems. This at least checks for a '?' following the
    // extension(s) we are interested in.
    const extensions = ['.js', '.js.map'];
    let result = fileName;
    extensions.some(extension => {
      if (fileName.includes(`${extension}?`)) {
        result = fileName.split(`${extension}?`)[0] + extension;
        return true;
      }
    });
    return result;
  }

{'fraction_non_alphanumeric': 0.1395617070357555, 'fraction_numerical': 0.0002883506343713956, 'mean_word_length': 2.7061965811965814, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2109256', 'n_tokens_mistral': 1053, 'n_tokens_neox': 1034, 'n_words': 214}