<commit_before>import test from 'ava';
import path from 'path';
import assign from "object-assign";
import MemoryFS from 'memory-fs';
import webpack from 'webpack';
import pify from 'pify';
import elmAssetsLoader from './index.js';

const outputPath = path.join(__dirname, 'build');
const fixturesPath = path.join(__dirname, "fixtures");
const elmMakePath = path.join(__dirname, 'node_modules/.bin/elm-make');

const globalConfig = (loaderConfig) => {
  return {
    context: fixturesPath,
    output: {
      path: outputPath,
      filename: 'main.js'
    },
    resolve: {
      modules: [
        fixturesPath
      ],
      extensions: ['.js', '.elm']
    },
    module: {
      rules: [
        {
          test: /\.elm$/,
          use: [
            loaderConfig,
            'elm-webpack-loader?cwd=' + fixturesPath + '&pathToMake=' + elmMakePath
          ]
        },
        {
          test: /\.svg$/,
          use: 'file-loader'
        }
      ]
    },
    plugins: [
      new webpack.NoErrorsPlugin()
    ]
  };
};

const makeConfig = (extraConfig, loaderOptions) => {
  const loaderConfig = {
    loader: path.join(__dirname, 'index.js'),
    options: loaderOptions
  };
  return assign({}, globalConfig(loaderConfig), extraConfig);
};

const compile = (config) => {
  return compileWithStats(config)
    .then(outputAndStats => outputAndStats.output);
};

const compileWithStats = (config) => {
  const fs = new MemoryFS();
  const compiler = webpack(config);
  compiler.outputFileSystem = fs;
  return pify(compiler.run.bind(compiler))()
    .then(stats => {
      if (stats.compilation.errors.length > 0) {
        throw stats.compilation.errors.map(error => error.message);
      }
      const exitPath = path.join(outputPath, 'main.js');
      const output = fs.readFileSync(exitPath).toString('utf-8');
      return {output: output, stats: stats.toJson()};
    });
}

/* finding the tagger in compiled JS code */

test('transform tagger in a package with hyphen', async t => {
  const config = makeConfig({
    entry: './Just'
  }, {
    package: 'elm-lang/core',
    module: 'Maybe',
    tagger: 'Just'
  });
  const result = await compile(config);
  t.regex(result, /Just\(__webpack_require__\(\d+\)\)/);
});

test('transform tagger not in package', async t => {
  const config = makeConfig({
    entry: './UserProject'
  }, {
    module: 'UserProject',
    tagger: 'Asset'
  });
  const result = await compile(config);
  t.regex(result, /Asset\(__webpack_require__\(\d+\)\)/);
});

test('do not transform tagger in different package', async t => {
  const config = makeConfig({
    entry: './MyMaybe'
  }, {
    module: 'MyMaybe',
    tagger: 'Just'
  });
  const result = await compile(config);
  t.regex(result, /Just\((["'])dont_touch_me.png\1\)/);
});

test('do not transform tagger in different module', async t => {
  const config = makeConfig({
    entry: './MyTag'
  }, {
    module: 'MyTag',
    tagger: 'Asset'
  });
  const result = await compile(config);
  t.regex(result, /Asset\((["'])dont_touch_me.png\1\)/);
});

/* argument handling */

test('cannot detect when tagger has multiple args', async t => {
  const config = makeConfig({
    entry: './MultiArg'
  }, {
    module: 'MultiArg',
    tagger: 'Asset'
  });
  const result = await compile(config);
  // inside an A2 call
  t.regex(result, /Asset,\s*(["'])elm_logo.svg\1,\s*\1elm_logo.svg\1\)/);
});

test('do not fail when something else is called with multiple args ', async t => {
  const config = makeConfig({
    entry: './IrrelevantMultiArg'
  }, {
    module: 'IrrelevantMultiArg',
    tagger: 'AssetPath'
  });
  const result = await compile(config);
  // inside an A2 call
  t.regex(result, /AssetPair,\s*(["'])elm_logo.svg\1,\s*\1elm_logo.svg\1\)/);
});

test('cannot detect if tagger with multiple values is called with a single arg', async t => {
  const config = makeConfig({
    entry: './PartialMultiArg'
  }, {
    module: 'PartialMultiArg',
    tagger: 'AssetPair'
  });
  const result = await compile(config);
  t.regex(result, /AssetPair\(__webpack_require__\(\d+\)\)/);
});

test('do not transform tagger that is actually a constant func', async t => {
  const config = makeConfig({
    entry: './NoArg'
  }, {
    module: 'NoArg',
    tagger: 'assetPath'
  });
  const result = await compile(config);
  t.regex(result, /assetPath\s*=\s*(["'])star.png\1/);
});

/* dynamicRequires */

test('dynamicRequires: default - warn', async t => {
  const config = makeConfig({
    entry: './ComplexCall'
  }, {
    module: 'ComplexCall',
    tagger: 'ComplexCallAsset'
  });
  const result = await compileWithStats(config);
  t.regex(result.output, /ComplexCallAsset\(A2/);
  t.regex(result.output, /ComplexCallAsset\(A2/);
  t.regex(result.stats.warnings[0], /will not be run through webpack.*ComplexCallAsset/);
});

test('dynamicRequires: ok - be silent', async t => {
  const config = makeConfig({
    entry: './ComplexCall'
  }, {
    module: 'ComplexCall',
    tagger: 'ComplexCallAsset',
    dynamicRequires: 'ok'
  });
  const result = await compileWithStats(config);
  t.regex(result.output, /ComplexCallAsset\(A2/);
  t.is(result.stats.warnings.length, 0);
});

test('dynamicRequires: warn - just warn', async t => {
  const config = makeConfig({
    entry: './ComplexCall'<commit_msg>:art: more verbose failure message should it fail<commit_after>import test from 'ava';
import path from 'path';
import assign from "object-assign";
import MemoryFS from 'memory-fs';
import webpack from 'webpack';
import pify from 'pify';
import elmAssetsLoader from './index.js';

const outputPath = path.join(__dirname, 'build');
const fixturesPath = path.join(__dirname, "fixtures");
const elmMakePath = path.join(__dirname, 'node_modules/.bin/elm-make');

const globalConfig = (loaderConfig) => {
  return {
    context: fixturesPath,
    output: {
      path: outputPath,
      filename: 'main.js'
    },
    resolve: {
      modules: [
        fixturesPath
      ],
      extensions: ['.js', '.elm']
    },
    module: {
      rules: [
        {
          test: /\.elm$/,
          use: [
            loaderConfig,
            'elm-webpack-loader?cwd=' + fixturesPath + '&pathToMake=' + elmMakePath
          ]
        },
        {
          test: /\.svg$/,
          use: 'file-loader'
        }
      ]
    },
    plugins: [
      new webpack.NoErrorsPlugin()
    ]
  };
};

const makeConfig = (extraConfig, loaderOptions) => {
  const loaderConfig = {
    loader: path.join(__dirname, 'index.js'),
    options: loaderOptions
  };
  return assign({}, globalConfig(loaderConfig), extraConfig);
};

const compile = (config) => {
  return compileWithStats(config)
    .then(outputAndStats => outputAndStats.output);
};

const compileWithStats = (config) => {
  const fs = new MemoryFS();
  const compiler = webpack(config);
  compiler.outputFileSystem = fs;
  return pify(compiler.run.bind(compiler))()
    .then(stats => {
      if (stats.compilation.errors.length > 0) {
        throw stats.compilation.errors.map(error => error.message);
      }
      const exitPath = path.join(outputPath, 'main.js');
      const output = fs.readFileSync(exitPath).toString('utf-8');
      return {output: output, stats: stats.toJson()};
    });
}

/* finding the tagger in compiled JS code */

test('transform tagger in a package with hyphen', async t => {
  const config = makeConfig({
    entry: './Just'
  }, {
    package: 'elm-lang/core',
    module: 'Maybe',
    tagger: 'Just'
  });
  const result = await compile(config);
  t.regex(result, /Just\(__webpack_require__\(\d+\)\)/);
});

test('transform tagger not in package', async t => {
  const config = makeConfig({
    entry: './UserProject'
  }, {
    module: 'UserProject',
    tagger: 'Asset'
  });
  const result = await compile(config);
  t.regex(result, /Asset\(__webpack_require__\(\d+\)\)/);
});

test('do not transform tagger in different package', async t => {
  const config = makeConfig({
    entry: './MyMaybe'
  }, {
    module: 'MyMaybe',
    tagger: 'Just'
  });
  const result = await compile(config);
  t.regex(result, /Just\((["'])dont_touch_me.png\1\)/);
});

test('do not transform tagger in different module', async t => {
  const config = makeConfig({
    entry: './MyTag'
  }, {
    module: 'MyTag',
    tagger: 'Asset'
  });
  const result = await compile(config);
  t.regex(result, /Asset\((["'])dont_touch_me.png\1\)/);
});

/* argument handling */

test('cannot detect when tagger has multiple args', async t => {
  const config = makeConfig({
    entry: './MultiArg'
  }, {
    module: 'MultiArg',
    tagger: 'Asset'
  });
  const result = await compile(config);
  // inside an A2 call
  t.regex(result, /Asset,\s*(["'])elm_logo.svg\1,\s*\1elm_logo.svg\1\)/);
});

test('do not fail when something else is called with multiple args ', async t => {
  const config = makeConfig({
    entry: './IrrelevantMultiArg'
  }, {
    module: 'IrrelevantMultiArg',
    tagger: 'AssetPath'
  });
  const result = await compile(config);
  // inside an A2 call
  t.regex(result, /AssetPair,\s*(["'])elm_logo.svg\1,\s*\1elm_logo.svg\1\)/);
});

test('cannot detect if tagger with multiple values is called with a single arg', async t => {
  const config = makeConfig({
    entry: './PartialMultiArg'
  }, {
    module: 'PartialMultiArg',
    tagger: 'AssetPair'
  });
  const result = await compile(config);
  t.regex(result, /AssetPair\(__webpack_require__\(\d+\)\)/);
});

test('do not transform tagger that is actually a constant func', async t => {
  const config = makeConfig({
    entry: './NoArg'
  }, {
    module: 'NoArg',
    tagger: 'assetPath'
  });
  const result = await compile(config);
  t.regex(result, /assetPath\s*=\s*(["'])star.png\1/);
});

/* dynamicRequires */

test('dynamicRequires: default - warn', async t => {
  const config = makeConfig({
    entry: './ComplexCall'
  }, {
    module: 'ComplexCall',
    tagger: 'ComplexCallAsset'
  });
  const result = await compileWithStats(config);
  t.regex(result.output, /ComplexCallAsset\(A2/);
  t.regex(result.output, /ComplexCallAsset\(A2/);
  t.regex(result.stats.warnings[0], /will not be run through webpack.*ComplexCallAsset/);
});

test('dynamicRequires: ok - be silent', async t => {
  const config = makeConfig({
    entry: './ComplexCall'
  }, {
    module: 'ComplexCall',
    tagger: 'ComplexCallAsset',
    dynamicRequires: 'ok'
  });
  const result = await compileWithStats(config);
  t.regex(result.output, /ComplexCallAsset\(A2/);
  t.deepEqual(result.stats.warnings, []);
});

test('dynamicRequires: warn - just warn', async t => {
  const config = makeConfig({
    entry: './ComplexCall'
{'fraction_non_alphanumeric': 0.16727716727716727, 'fraction_numerical': 0.003287310979618672, 'mean_word_length': 3.1319363601086536, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 41, 'https://': 0, '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': '2686463', 'n_tokens_mistral': 3446, 'n_tokens_neox': 3417, 'n_words': 839}