<commit_before>// Compares .sol files to their .sol.js counterparts,
// determines which .sol files have been updated.

const path = require("path");
const async = require("async");
const fs = require("fs");
const Parser = require("./parser");
const CompilerSupplier = require("./compilerSupplier");
const expect = require("truffle-expect");
const find_contracts = require("truffle-contract-sources");
const semver = require("semver");
const debug = require("debug")("compile:profiler"); // eslint-disable-line no-unused-vars

module.exports = {
  updated(options, callback) {
    expect.options(options, ["resolver"]);

    const contracts_directory = options.contracts_directory;
    const build_directory = options.contracts_build_directory;

    function getFiles(done) {
      if (options.files) {
        done(null, options.files);
      } else {
        find_contracts(contracts_directory, done);
      }
    }

    const sourceFilesArtifacts = {};
    const sourceFilesArtifactsUpdatedTimes = {};

    const updatedFiles = [];

    async.series(
      [
        // Get all the source files and create an object out of them.
        c => {
          getFiles((err, files) => {
            if (err) return c(err);

            // Use an object for O(1) access.
            files.forEach(sourceFile => {
              sourceFilesArtifacts[sourceFile] = [];
            });

            c();
          });
        },
        // Get all the artifact files, and read them, parsing them as JSON
        c => {
          fs.readdir(build_directory, (err, build_files) => {
            if (err) {
              // The build directory may not always exist.
              if (err.message.includes("ENOENT: no such file or directory")) {
                // Ignore it.
                build_files = [];
              } else {
                return c(err);
              }
            }

            build_files = build_files.filter(
              build_file => path.extname(build_file) === ".json"
            );

            async.map(
              build_files,
              (buildFile, finished) => {
                fs.readFile(
                  path.join(build_directory, buildFile),
                  "utf8",
                  (err, body) => {
                    if (err) return finished(err);
                    finished(null, body);
                  }
                );
              },
              (err, jsonData) => {
                if (err) return c(err);

                try {
                  for (let i = 0; i < jsonData.length; i++) {
                    const data = JSON.parse(jsonData[i]);

                    // In case there are artifacts from other source locations.
                    if (sourceFilesArtifacts[data.sourcePath] == null) {
                      sourceFilesArtifacts[data.sourcePath] = [];
                    }

                    sourceFilesArtifacts[data.sourcePath].push(data);
                  }
                } catch (e) {
                  return c(e);
                }

                c();
              }
            );
          });
        },
        c => {
          // Get the minimum updated time for all of a source file's artifacts
          // (note: one source file might have multiple artifacts).
          Object.keys(sourceFilesArtifacts).forEach(sourceFile => {
            const artifacts = sourceFilesArtifacts[sourceFile];<commit_msg>Add a specific error for invalid artifacts<commit_after>// Compares .sol files to their .sol.js counterparts,
// determines which .sol files have been updated.

const path = require("path");
const async = require("async");
const fs = require("fs");
const Parser = require("./parser");
const CompilerSupplier = require("./compilerSupplier");
const expect = require("truffle-expect");
const find_contracts = require("truffle-contract-sources");
const semver = require("semver");
const debug = require("debug")("compile:profiler"); // eslint-disable-line no-unused-vars

module.exports = {
  updated(options, callback) {
    expect.options(options, ["resolver"]);

    const contracts_directory = options.contracts_directory;
    const build_directory = options.contracts_build_directory;

    function getFiles(done) {
      if (options.files) {
        done(null, options.files);
      } else {
        find_contracts(contracts_directory, done);
      }
    }

    const sourceFilesArtifacts = {};
    const sourceFilesArtifactsUpdatedTimes = {};

    const updatedFiles = [];

    async.series(
      [
        // Get all the source files and create an object out of them.
        c => {
          getFiles((err, files) => {
            if (err) return c(err);

            // Use an object for O(1) access.
            files.forEach(sourceFile => {
              sourceFilesArtifacts[sourceFile] = [];
            });

            c();
          });
        },
        // Get all the artifact files, and read them, parsing them as JSON
        c => {
          fs.readdir(build_directory, (err, build_files) => {
            if (err) {
              // The build directory may not always exist.
              if (err.message.includes("ENOENT: no such file or directory")) {
                // Ignore it.
                build_files = [];
              } else {
                return c(err);
              }
            }

            build_files = build_files.filter(
              build_file => path.extname(build_file) === ".json"
            );

            async.map(
              build_files,
              (buildFile, finished) => {
                fs.readFile(
                  path.join(build_directory, buildFile),
                  "utf8",
                  (err, body) => {
                    if (err) return finished(err);
                    finished(null, { file: buildFile, body });
                  }
                );
              },
              (err, jsonData) => {
                if (err) return c(err);

                for (let i = 0; i < jsonData.length; i++) {
                  try {
                    const data = JSON.parse(jsonData[i].body);

                    // In case there are artifacts from other source locations.
                    if (sourceFilesArtifacts[data.sourcePath] == null) {
                      sourceFilesArtifacts[data.sourcePath] = [];
                    }

                    sourceFilesArtifacts[data.sourcePath].push(data);
                  } catch (e) {
                    // JSON.parse throws SyntaxError objects
                    return e instanceof SyntaxError
                      ? c(new Error("Invalid artifact: " + jsonData[i].file))
                      : c(e);
                  }
                }

                c();
              }
            );
          });
        },
        c => {
          // Get the minimum updated time for all of a source file's artifacts
          // (note: one source file might have multiple artifacts).
          Object.keys(sourceFilesArtifacts).forEach(sourceFile => {
            const artifacts = sourceFilesArtifacts[sourceFile];
{'fraction_non_alphanumeric': 0.1124946936465261, 'fraction_numerical': 0.0008490165558228386, 'mean_word_length': 1.5278969957081545, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 25, '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': '804548', 'n_tokens_mistral': 1831, 'n_tokens_neox': 1739, 'n_words': 456}