<commit_before>;'use strict'
var crypto = require('crypto')
var eachAsync = require('each-async')
var fs = require('fs')
var chalk = require('chalk')
var bindArgs = require('bind-args')

module.exports = function (grunt) {
  grunt.registerMultiTask(
    'export-filerev',
    'Calculate file revision based on file content and export revision by' +
    'callback for your custom useage',
    bindArgs(exportFilerev, grunt)
  )
}

function exportFilerev (grunt) {
  var taskDone = this.async()
  var HEX
  var options = this.options({
    algorithm: 'md5',
    length: 8,
    // Optional values: `16`, `32`
    digit: HEX = 16,
    onFileDone: noop,
    onDone: noop
  })
  var summary = {}
  var task = this

  eachAsync(task.files, function (el, i, eachDone) {
    eachAsync(el.src, function (srcFile, j, eachDone2) {
      // readable and writable stream
      var hash = crypto.createHash(options.algorithm)
      var fileStream = fs.createReadStream(srcFile)
      .on('readable', function () {
        var buffer = fileStream.read()
        hash.update(buffer)
      })
      .on('end', function () {
        var revision = hash.digest('hex')
        if (options.digit !== HEX) {
          revision = parseInt(revision, HEX).toString(options.digit)
        }
        options.onFileDone(srcFile, revision)
        summary[srcFile] = revision
        grunt.verbose.writeln('Revision: ' + chalk.cyan(srcFile) + ' -> ' +
          chalk.cyan(revision)
        )
        eachDone2()
      })
    }, function finish2 (error) {
      if (error) {
        grunt.fail.fatal(error)
      }
      eachDone()
    })
  }, function finish (error) {
    if (error) {
      grunt.fail.fatal(error)
    }
    grunt.log.ok(
      'Export file revision:\n' + JSON.stringify(summary, null, 2)
    )
    grunt.config(this.name + ':' + this.target, summary)
    options.onDone(summary)
    taskDone()
  })
}

function noop () {}
<commit_msg>1) Access all `src` files by `this.filesSrc`, because this task is read only and doesn't care about destination file paths; 2) Callbacks `onFileDone` and `onAllFilesDone` support asynchronize operation;<commit_after>;'use strict'
var crypto = require('crypto')
var eachAsync = require('each-async')
var fs = require('fs')
var chalk = require('chalk')
var bindArgs = require('bind-args')

module.exports = function (grunt) {
  grunt.registerMultiTask(
    'export-filerev',
    'Calculate file revision based on file content and export revision by' +
    'callback for your custom useage',
    bindArgs(exportFilerev, grunt)
  )
}

function exportFilerev (grunt) {
  var taskDone = this.async()
  var HEX
  var options = this.options({
    algorithm: 'md5',
    length: 8,
    // Optional values: `16`, `32`
    digit: HEX = 16,
    onFileDone: function (revision, file, done) {
      done()
    },
    onAllFilesDone: function (summary, done) {
      done()
    }
  })
  var summary = {}
  var task = this
  var filesSrc = task.filesSrc.filter(function (file) {
    return grunt.file.isFile(file)
  })

  eachAsync(
    filesSrc,
    function (file, i, eachDone) {
      // `hash` is readable and writeable stream
      var hash = crypto.createHash(options.algorithm)
      var readStream = fs.createReadStream(file)
      .on('readable', function () {
        var buffer = readStream.read()
        hash.update(buffer)
      })
      .on('end', function () {
        var revision = hash.digest('hex')
        // if (options.radix !== HEX) {
        //   revision = parseInt(revision, HEX).toString(options.radix)
        // }
        summary[file] = revision
        grunt.verbose.writeln(
          'Revision: ' + chalk.cyan(file) + '->' + chalk.cyan(revision)
        )
        options.onFileDone(revision, file, eachDone)
      })
    },
    function finish (error) {
      if (error) {
        grunt.fail.fatal(error)
      }
      grunt.log.writeln(
        chalk.cyan('Export the summary of file revision:\n') + JSON.stringify(summary, null, 2)
      )
      grunt.config(task.nameArgs, summary)
      options.onAllFilesDone(summary, taskDone)
    }
  )
}

{'fraction_non_alphanumeric': 0.13310496696843652, 'fraction_numerical': 0.005627599706386102, 'mean_word_length': 2.659803043867502, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '321447', 'n_tokens_mistral': 1332, 'n_tokens_neox': 1291, 'n_words': 318}