| /** | 
|  * @fileoverview Utility for caching lint results. | 
|  * @author Kevin Partington | 
|  */ | 
| "use strict"; | 
|   | 
| //----------------------------------------------------------------------------- | 
| // Requirements | 
| //----------------------------------------------------------------------------- | 
|   | 
| const assert = require("assert"); | 
| const fs = require("fs"); | 
| const fileEntryCache = require("file-entry-cache"); | 
| const stringify = require("json-stable-stringify-without-jsonify"); | 
| const pkg = require("../../package.json"); | 
| const hash = require("./hash"); | 
|   | 
| //----------------------------------------------------------------------------- | 
| // Helpers | 
| //----------------------------------------------------------------------------- | 
|   | 
| const configHashCache = new WeakMap(); | 
| const nodeVersion = process && process.version; | 
|   | 
| /** | 
|  * Calculates the hash of the config | 
|  * @param {ConfigArray} config The config. | 
|  * @returns {string} The hash of the config | 
|  */ | 
| function hashOfConfigFor(config) { | 
|     if (!configHashCache.has(config)) { | 
|         configHashCache.set(config, hash(`${pkg.version}_${nodeVersion}_${stringify(config)}`)); | 
|     } | 
|   | 
|     return configHashCache.get(config); | 
| } | 
|   | 
| //----------------------------------------------------------------------------- | 
| // Public Interface | 
| //----------------------------------------------------------------------------- | 
|   | 
| /** | 
|  * Lint result cache. This wraps around the file-entry-cache module, | 
|  * transparently removing properties that are difficult or expensive to | 
|  * serialize and adding them back in on retrieval. | 
|  */ | 
| class LintResultCache { | 
|   | 
|     /** | 
|      * Creates a new LintResultCache instance. | 
|      * @param {string} cacheFileLocation The cache file location. | 
|      *   configuration lookup by file path). | 
|      */ | 
|     constructor(cacheFileLocation) { | 
|         assert(cacheFileLocation, "Cache file location is required"); | 
|   | 
|         this.fileEntryCache = fileEntryCache.create(cacheFileLocation); | 
|     } | 
|   | 
|     /** | 
|      * Retrieve cached lint results for a given file path, if present in the | 
|      * cache. If the file is present and has not been changed, rebuild any | 
|      * missing result information. | 
|      * @param {string} filePath The file for which to retrieve lint results. | 
|      * @param {ConfigArray} config The config of the file. | 
|      * @returns {Object|null} The rebuilt lint results, or null if the file is | 
|      *   changed or not in the filesystem. | 
|      */ | 
|     getCachedLintResults(filePath, config) { | 
|   | 
|         /* | 
|          * Cached lint results are valid if and only if: | 
|          * 1. The file is present in the filesystem | 
|          * 2. The file has not changed since the time it was previously linted | 
|          * 3. The ESLint configuration has not changed since the time the file | 
|          *    was previously linted | 
|          * If any of these are not true, we will not reuse the lint results. | 
|          */ | 
|   | 
|         const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath); | 
|         const hashOfConfig = hashOfConfigFor(config); | 
|         const changed = fileDescriptor.changed || fileDescriptor.meta.hashOfConfig !== hashOfConfig; | 
|   | 
|         if (fileDescriptor.notFound || changed) { | 
|             return null; | 
|         } | 
|   | 
|         // If source is present but null, need to reread the file from the filesystem. | 
|         if (fileDescriptor.meta.results && fileDescriptor.meta.results.source === null) { | 
|             fileDescriptor.meta.results.source = fs.readFileSync(filePath, "utf-8"); | 
|         } | 
|   | 
|         return fileDescriptor.meta.results; | 
|     } | 
|   | 
|     /** | 
|      * Set the cached lint results for a given file path, after removing any | 
|      * information that will be both unnecessary and difficult to serialize. | 
|      * Avoids caching results with an "output" property (meaning fixes were | 
|      * applied), to prevent potentially incorrect results if fixes are not | 
|      * written to disk. | 
|      * @param {string} filePath The file for which to set lint results. | 
|      * @param {ConfigArray} config The config of the file. | 
|      * @param {Object} result The lint result to be set for the file. | 
|      * @returns {void} | 
|      */ | 
|     setCachedLintResults(filePath, config, result) { | 
|         if (result && Object.prototype.hasOwnProperty.call(result, "output")) { | 
|             return; | 
|         } | 
|   | 
|         const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath); | 
|   | 
|         if (fileDescriptor && !fileDescriptor.notFound) { | 
|   | 
|             // Serialize the result, except that we want to remove the file source if present. | 
|             const resultToSerialize = Object.assign({}, result); | 
|   | 
|             /* | 
|              * Set result.source to null. | 
|              * In `getCachedLintResults`, if source is explicitly null, we will | 
|              * read the file from the filesystem to set the value again. | 
|              */ | 
|             if (Object.prototype.hasOwnProperty.call(resultToSerialize, "source")) { | 
|                 resultToSerialize.source = null; | 
|             } | 
|   | 
|             fileDescriptor.meta.results = resultToSerialize; | 
|             fileDescriptor.meta.hashOfConfig = hashOfConfigFor(config); | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * Persists the in-memory cache to disk. | 
|      * @returns {void} | 
|      */ | 
|     reconcile() { | 
|         this.fileEntryCache.reconcile(); | 
|     } | 
| } | 
|   | 
| module.exports = LintResultCache; |