Repository: istanbuljs/nyc
Pull request #1145 (2019-07-12 00:45:37)

feat: Use istanbul-lib-processinfo

coveralls: 
[![Coverage Status](https://coveralls.io/builds/24518608/badge)](https://coveralls.io/builds/24518608)

Coverage increased (+0.4%) to 97.21% when pulling **763bd514a270f9aab2c502d01527c3f7f94f45f4 on coreyfarrell:use-processinfo** into **00c3b3440a5b2ffe11b9c19ae4e08ad2f5b70e33 on istanbuljs:master**.

isaacs: Looks good to me!

Patch:
diff --git a/index.js b/index.js
index 2310f57..ffe1b50 100755
--- a/index.js
+++ b/index.js
@@ -10,6 +10,7 @@ const glob = require('glob')
 const Hash = require('./lib/hash')
 const libCoverage = require('istanbul-lib-coverage')
 const libHook = require('istanbul-lib-hook')
+const { ProcessInfo, ProcessDB } = require('istanbul-lib-processinfo')
 const libReport = require('istanbul-lib-report')
 const mkdirp = require('make-dir')
 const Module = require('module')
@@ -24,8 +25,6 @@ const util = require('util')
 
 const debugLog = util.debuglog('nyc')
 
-const ProcessInfo = require('./lib/process.js')
-
 /* istanbul ignore next */
 if (/self-coverage/.test(__dirname)) {
   require('../self-coverage-helper')
@@ -87,7 +86,9 @@ class NYC {
     this.hookRunInThisContext = config.hookRunInThisContext
     this.fakeRequire = null
 
-    this.processInfo = new ProcessInfo(config && config._processInfo)
+    this.processInfo = new ProcessInfo(Object.assign({}, config._processInfo, {
+      directory: path.resolve(this.tempDirectory(), 'processinfo')
+    }))
 
     this.hashCache = {}
   }
@@ -308,7 +309,7 @@ class NYC {
     mkdirp.sync(this.tempDirectory())
     if (this.cache) mkdirp.sync(this.cacheDirectory)
 
-    mkdirp.sync(this.processInfoDirectory())
+    mkdirp.sync(this.processInfo.directory)
   }
 
   reset () {
@@ -364,12 +365,7 @@ class NYC {
 
     this.processInfo.coverageFilename = coverageFilename
     this.processInfo.files = Object.keys(coverage)
-
-    fs.writeFileSync(
-      path.resolve(this.processInfoDirectory(), id + '.json'),
-      JSON.stringify(this.processInfo),
-      'utf-8'
-    )
+    this.processInfo.save()
   }
 
   getCoverageMapFromAllCoverageFiles (baseDirectory) {
@@ -412,84 +408,14 @@ class NYC {
     }
   }
 
-  // XXX(@isaacs) Index generation should move to istanbul-lib-processinfo
   writeProcessIndex () {
-    const dir = this.processInfoDirectory()
-    const pidToUid = new Map()
-    const infoByUid = new Map()
-    const eidToUid = new Map()
-    const infos = fs.readdirSync(dir).filter(f => f !== 'index.json').map(f => {
-      try {
-        const info = JSON.parse(fs.readFileSync(path.resolve(dir, f), 'utf-8'))
-        info.children = []
-        pidToUid.set(info.uuid, info.pid)
-        pidToUid.set(info.pid, info.uuid)
-        infoByUid.set(info.uuid, info)
-        if (info.externalId) {
-          eidToUid.set(info.externalId, info.uuid)
-        }
-        return info
-      } catch (er) {
-        return null
-      }
-    }).filter(Boolean)
-
-    // create all the parent-child links and write back the updated info
-    infos.forEach(info => {
-      if (info.parent) {
-        const parentInfo = infoByUid.get(info.parent)
-        if (parentInfo && !parentInfo.children.includes(info.uuid)) {
-          parentInfo.children.push(info.uuid)
-        }
-      }
-    })
-
-    // figure out which files were touched by each process.
-    const files = infos.reduce((files, info) => {
-      info.files.forEach(f => {
-        files[f] = files[f] || []
-        files[f].push(info.uuid)
-      })
-      return files
-    }, {})
-
-    // build the actual index!
-    const index = infos.reduce((index, info) => {
-      index.processes[info.uuid] = {}
-      index.processes[info.uuid].parent = info.parent
-      if (info.externalId) {
-        if (index.externalIds[info.externalId]) {
-          throw new Error(`External ID ${info.externalId} used by multiple processes`)
-        }
-        index.processes[info.uuid].externalId = info.externalId
-        index.externalIds[info.externalId] = {
-          root: info.uuid,
-          children: info.children
-        }
-      }
-      index.processes[info.uuid].children = Array.from(info.children)
-      return index
-    }, { processes: {}, files: files, externalIds: {} })
-
-    // flatten the descendant sets of all the externalId procs
-    Object.keys(index.externalIds).forEach(eid => {
-      const { children } = index.externalIds[eid]
-      // push the next generation onto the list so we accumulate them all
-      for (let i = 0; i < children.length; i++) {
-        const nextGen = index.processes[children[i]].children
-        if (nextGen && nextGen.length) {
-          children.push(...nextGen.filter(uuid => children.indexOf(uuid) === -1))
-        }
-      }
-    })
-
-    fs.writeFileSync(path.resolve(dir, 'index.json'), JSON.stringify(index))
+    const db = new ProcessDB(this.processInfo.directory)
+    db.writeIndex()
   }
 
   showProcessTree () {
-    var processTree = ProcessInfo.buildProcessTree(this._loadProcessInfos())
-
-    console.log(processTree.render(this))
+    const db = new ProcessDB(this.processInfo.directory)
+    console.log(db.renderTree(this))
   }
 
   checkCoverage (thresholds, perFile) {
@@ -521,28 +447,6 @@ class NYC {
     })
   }
 
-  _loadProcessInfos () {
-    return fs.readdirSync(this.processInfoDirectory()).map(f => {
-      let data
-      try {
-        data = JSON.parse(fs.readFileSync(
-          path.resolve(this.processInfoDirectory(), f),
-          'utf-8'
-        ))
-      } catch (e) { // handle corrupt JSON output.
-        return null
-      }
-      if (f !== 'index.json') {
-        data.nodes = []
-        data = new ProcessInfo(data)
-      }
-      return { file: path.basename(f, '.json'), data: data }
-    }).filter(Boolean).reduce((infos, info) => {
-      infos[info.file] = info.data
-      return infos
-    }, {})
-  }
-
   eachReport (filenames, iterator, baseDirectory) {
     baseDirectory = baseDirectory || this.tempDirectory()
 
@@ -588,10 +492,6 @@ class NYC {
   reportDirectory () {
     return path.resolve(this.cwd, this._reportDir)
   }
-
-  processInfoDirectory () {
-    return path.resolve(this.tempDirectory(), 'processinfo')
-  }
 }
 
 module.exports = NYC
diff --git a/lib/process.js b/lib/process.js
deleted file mode 100644
index 37b1e91..0000000
--- a/lib/process.js
+++ /dev/null
@@ -1,91 +0,0 @@
-const archy = require('archy')
-const libCoverage = require('istanbul-lib-coverage')
-const uuid = require('uuid/v4')
-
-function ProcessInfo (defaults) {
-  defaults = defaults || {}
-
-  this.uuid = null
-  this.parent = null
-  this.pid = String(process.pid)
-  this.argv = process.argv
-  this.execArgv = process.execArgv
-  this.cwd = process.cwd()
-  this.time = Date.now()
-  this.ppid = null
-  this.coverageFilename = null
-
-  for (var key in defaults) {
-    this[key] = defaults[key]
-  }
-
-  if (!this.uuid) {
-    this.uuid = uuid()
-  }
-}
-
-Object.defineProperty(ProcessInfo.prototype, 'label', {
-  get: function () {
-    if (this._label) {
-      return this._label
-    }
-
-    var covInfo = ''
-    if (this._coverageMap) {
-      covInfo = '\n  ' + this._coverageMap.getCoverageSummary().lines.pct + ' % Lines'
-    }
-    return this.argv.join(' ') + covInfo
-  }
-})
-
-ProcessInfo.buildProcessTree = function (infos) {
-  const treeRoot = new ProcessInfo({ _label: 'nyc', nodes: [] })
-  const index = infos.index
-  for (const id in index.processes) {
-    const node = infos[id]
-    if (!node) {
-      throw new Error(`Invalid entry in processinfo index: ${id}`)
-    }
-    const idx = index.processes[id]
-    node.nodes = idx.children.map(id => infos[id]).sort((a, b) => a.time - b.time)
-    if (!node.parent) {
-      treeRoot.nodes.push(node)
-    }
-  }
-
-  return treeRoot
-}
-
-ProcessInfo.prototype.getCoverageMap = function (merger) {
-  if (this._coverageMap) {
-    return this._coverageMap
-  }
-
-  var childMaps = this.nodes.map(function (child) {
-    return child.getCoverageMap(merger)
-  })
-
-  this._coverageMap = merger([this.coverageFilename], childMaps)
-
-  return this._coverageMap
-}
-
-ProcessInfo.prototype.render = function (nyc) {
-  this.getCoverageMap(function (filenames, maps) {
-    var map = libCoverage.createCoverageMap({})
-
-    nyc.eachReport(filenames, function (report) {
-      map.merge(report)
-    })
-
-    maps.forEach(function (otherMap) {
-      map.merge(otherMap)
-    })
-
-    return map
-  })
-
-  return archy(this)
-}
-
-module.exports = ProcessInfo
diff --git a/package-lock.json b/package-lock.json
index eb10c4a..bcc8fb9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2649,14 +2649,13 @@
       }
     },
     "istanbul-lib-processinfo": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-1.0.0.tgz",
-      "integrity": "sha512-FY0cPmWa4WoQNlvB8VOcafiRoB5nB+l2Pz2xGuXHRSy1KM8QFOYfz/rN+bGMCAeejrY3mrpF5oJHcN0s/garCg==",
-      "dev": true,
+      "version": "github:istanbuljs/istanbul-lib-processinfo#c6cfcf6bfee8249223fb72d8b7465de1ce944c91",
+      "from": "github:istanbuljs/istanbul-lib-processinfo#master",
       "requires": {
         "archy": "^1.0.0",
         "cross-spawn": "^6.0.5",
-        "istanbul-lib-coverage": "^2.0.3",
+        "istanbul-lib-coverage": "^3.0.0-alpha.0",
+        "make-dir": "^3.0.0",
         "rimraf": "^2.6.3",
         "uuid": "^3.3.2"
       },
@@ -2665,7 +2664,6 @@
           "version": "6.0.5",
           "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
           "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
-          "dev": true,
           "requires": {
             "nice-try": "^1.0.4",
             "path-key": "^2.0.1",
@@ -2674,17 +2672,10 @@
             "which": "^1.2.9"
           }
         },
-        "istanbul-lib-coverage": {
-          "version": "2.0.5",
-          "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
-          "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
-          "dev": true
-        },
         "semver": {
           "version": "5.7.0",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
-          "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
-          "dev": true
+          "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
         }
       }
     },
@@ -3344,8 +3335,7 @@
     "nice-try": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
-      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
-      "dev": true
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
     },
     "node-modules-regexp": {
       "version": "1.0.0",
@@ -3948,8 +3938,7 @@
     "path-key": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
-      "dev": true
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
     },
     "path-parse": {
       "version": "1.0.6",
@@ -4482,7 +4471,6 @@
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
       "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
-      "dev": true,
       "requires": {
         "shebang-regex": "^1.0.0"
       }
@@ -4490,8 +4478,7 @@
     "shebang-regex": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
-      "dev": true
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
     },
     "signal-exit": {
       "version": "3.0.2",
@@ -5420,6 +5407,19 @@
           "bundled": true,
           "dev": true
         },
+        "cross-spawn": {
+          "version": "6.0.5",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+          "dev": true,
+          "requires": {
+            "nice-try": "^1.0.4",
+            "path-key": "^2.0.1",
+            "semver": "^5.5.0",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
         "csstype": {
           "version": "2.6.4",
           "bundled": true,
@@ -5621,6 +5621,25 @@
           "bundled": true,
           "dev": true
         },
+        "istanbul-lib-coverage": {
+          "version": "2.0.5",
+          "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
+          "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
+          "dev": true
+        },
+        "istanbul-lib-processinfo": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-1.0.0.tgz",
+          "integrity": "sha512-FY0cPmWa4WoQNlvB8VOcafiRoB5nB+l2Pz2xGuXHRSy1KM8QFOYfz/rN+bGMCAeejrY3mrpF5oJHcN0s/garCg==",
+          "dev": true,
+          "requires": {
+            "archy": "^1.0.0",
+            "cross-spawn": "^6.0.5",
+            "istanbul-lib-coverage": "^2.0.3",
+            "rimraf": "^2.6.3",
+            "uuid": "^3.3.2"
+          }
+        },
         "js-tokens": {
           "version": "3.0.2",
           "bundled": true,
@@ -5887,6 +5906,12 @@
             "object-assign": "^4.1.1"
           }
         },
+        "semver": {
+          "version": "5.7.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
+          "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
+          "dev": true
+        },
         "signal-exit": {
           "version": "3.0.2",
           "bundled": true,
diff --git a/package.json b/package.json
index 694c2a4..322c382 100644
--- a/package.json
+++ b/package.json
@@ -68,7 +68,6 @@
   "author": "Ben Coe <ben@npmjs.com>",
   "license": "ISC",
   "dependencies": {
-    "archy": "^1.0.0",
     "caching-transform": "^4.0.0",
     "convert-source-map": "^1.6.0",
     "cp-file": "^7.0.0",
@@ -79,6 +78,7 @@
     "istanbul-lib-coverage": "^3.0.0-alpha.0",
     "istanbul-lib-hook": "^3.0.0-alpha.0",
     "istanbul-lib-instrument": "^4.0.0-alpha.0",
+    "istanbul-lib-processinfo": "istanbuljs/istanbul-lib-processinfo#master",
     "istanbul-lib-report": "^3.0.0-alpha.0",
     "istanbul-lib-source-maps": "^4.0.0-alpha.0",
     "istanbul-reports": "^3.0.0-alpha.1",


Test patch:
diff --git a/tap-snapshots/test-nyc-integration.js-TAP.test.js b/tap-snapshots/test-nyc-integration.js-TAP.test.js
index ffe6bfc..4635391 100644
--- a/tap-snapshots/test-nyc-integration.js-TAP.test.js
+++ b/tap-snapshots/test-nyc-integration.js-TAP.test.js
@@ -185,6 +185,7 @@ All files               |   90.91 |       70 |     100 |     100 |
  selfspawn-fibonacci.js |   90.91 |       70 |     100 |     100 | 4,25,27           
 ------------------------|---------|----------|---------|---------|-------------------
 nyc
+│   100 % Lines
 └─┬ node ./selfspawn-fibonacci.js 5
   │   100 % Lines
   ├─┬ node ./selfspawn-fibonacci.js 4