source: imaps-frontend/node_modules/eslint/lib/cli-engine/lint-result-cache.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/**
2 * @fileoverview Utility for caching lint results.
3 * @author Kevin Partington
4 */
5"use strict";
6
7//-----------------------------------------------------------------------------
8// Requirements
9//-----------------------------------------------------------------------------
10
11const assert = require("assert");
12const fs = require("fs");
13const fileEntryCache = require("file-entry-cache");
14const stringify = require("json-stable-stringify-without-jsonify");
15const pkg = require("../../package.json");
16const hash = require("./hash");
17
18const debug = require("debug")("eslint:lint-result-cache");
19
20//-----------------------------------------------------------------------------
21// Helpers
22//-----------------------------------------------------------------------------
23
24const configHashCache = new WeakMap();
25const nodeVersion = process && process.version;
26
27const validCacheStrategies = ["metadata", "content"];
28const invalidCacheStrategyErrorMessage = `Cache strategy must be one of: ${validCacheStrategies
29 .map(strategy => `"${strategy}"`)
30 .join(", ")}`;
31
32/**
33 * Tests whether a provided cacheStrategy is valid
34 * @param {string} cacheStrategy The cache strategy to use
35 * @returns {boolean} true if `cacheStrategy` is one of `validCacheStrategies`; false otherwise
36 */
37function isValidCacheStrategy(cacheStrategy) {
38 return (
39 validCacheStrategies.includes(cacheStrategy)
40 );
41}
42
43/**
44 * Calculates the hash of the config
45 * @param {ConfigArray} config The config.
46 * @returns {string} The hash of the config
47 */
48function hashOfConfigFor(config) {
49 if (!configHashCache.has(config)) {
50 configHashCache.set(config, hash(`${pkg.version}_${nodeVersion}_${stringify(config)}`));
51 }
52
53 return configHashCache.get(config);
54}
55
56//-----------------------------------------------------------------------------
57// Public Interface
58//-----------------------------------------------------------------------------
59
60/**
61 * Lint result cache. This wraps around the file-entry-cache module,
62 * transparently removing properties that are difficult or expensive to
63 * serialize and adding them back in on retrieval.
64 */
65class LintResultCache {
66
67 /**
68 * Creates a new LintResultCache instance.
69 * @param {string} cacheFileLocation The cache file location.
70 * @param {"metadata" | "content"} cacheStrategy The cache strategy to use.
71 */
72 constructor(cacheFileLocation, cacheStrategy) {
73 assert(cacheFileLocation, "Cache file location is required");
74 assert(cacheStrategy, "Cache strategy is required");
75 assert(
76 isValidCacheStrategy(cacheStrategy),
77 invalidCacheStrategyErrorMessage
78 );
79
80 debug(`Caching results to ${cacheFileLocation}`);
81
82 const useChecksum = cacheStrategy === "content";
83
84 debug(
85 `Using "${cacheStrategy}" strategy to detect changes`
86 );
87
88 this.fileEntryCache = fileEntryCache.create(
89 cacheFileLocation,
90 void 0,
91 useChecksum
92 );
93 this.cacheFileLocation = cacheFileLocation;
94 }
95
96 /**
97 * Retrieve cached lint results for a given file path, if present in the
98 * cache. If the file is present and has not been changed, rebuild any
99 * missing result information.
100 * @param {string} filePath The file for which to retrieve lint results.
101 * @param {ConfigArray} config The config of the file.
102 * @returns {Object|null} The rebuilt lint results, or null if the file is
103 * changed or not in the filesystem.
104 */
105 getCachedLintResults(filePath, config) {
106
107 /*
108 * Cached lint results are valid if and only if:
109 * 1. The file is present in the filesystem
110 * 2. The file has not changed since the time it was previously linted
111 * 3. The ESLint configuration has not changed since the time the file
112 * was previously linted
113 * If any of these are not true, we will not reuse the lint results.
114 */
115 const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
116 const hashOfConfig = hashOfConfigFor(config);
117 const changed =
118 fileDescriptor.changed ||
119 fileDescriptor.meta.hashOfConfig !== hashOfConfig;
120
121 if (fileDescriptor.notFound) {
122 debug(`File not found on the file system: ${filePath}`);
123 return null;
124 }
125
126 if (changed) {
127 debug(`Cache entry not found or no longer valid: ${filePath}`);
128 return null;
129 }
130
131 const cachedResults = fileDescriptor.meta.results;
132
133 // Just in case, not sure if this can ever happen.
134 if (!cachedResults) {
135 return cachedResults;
136 }
137
138 /*
139 * Shallow clone the object to ensure that any properties added or modified afterwards
140 * will not be accidentally stored in the cache file when `reconcile()` is called.
141 * https://github.com/eslint/eslint/issues/13507
142 * All intentional changes to the cache file must be done through `setCachedLintResults()`.
143 */
144 const results = { ...cachedResults };
145
146 // If source is present but null, need to reread the file from the filesystem.
147 if (results.source === null) {
148 debug(`Rereading cached result source from filesystem: ${filePath}`);
149 results.source = fs.readFileSync(filePath, "utf-8");
150 }
151
152 return results;
153 }
154
155 /**
156 * Set the cached lint results for a given file path, after removing any
157 * information that will be both unnecessary and difficult to serialize.
158 * Avoids caching results with an "output" property (meaning fixes were
159 * applied), to prevent potentially incorrect results if fixes are not
160 * written to disk.
161 * @param {string} filePath The file for which to set lint results.
162 * @param {ConfigArray} config The config of the file.
163 * @param {Object} result The lint result to be set for the file.
164 * @returns {void}
165 */
166 setCachedLintResults(filePath, config, result) {
167 if (result && Object.prototype.hasOwnProperty.call(result, "output")) {
168 return;
169 }
170
171 const fileDescriptor = this.fileEntryCache.getFileDescriptor(filePath);
172
173 if (fileDescriptor && !fileDescriptor.notFound) {
174 debug(`Updating cached result: ${filePath}`);
175
176 // Serialize the result, except that we want to remove the file source if present.
177 const resultToSerialize = Object.assign({}, result);
178
179 /*
180 * Set result.source to null.
181 * In `getCachedLintResults`, if source is explicitly null, we will
182 * read the file from the filesystem to set the value again.
183 */
184 if (Object.prototype.hasOwnProperty.call(resultToSerialize, "source")) {
185 resultToSerialize.source = null;
186 }
187
188 fileDescriptor.meta.results = resultToSerialize;
189 fileDescriptor.meta.hashOfConfig = hashOfConfigFor(config);
190 }
191 }
192
193 /**
194 * Persists the in-memory cache to disk.
195 * @returns {void}
196 */
197 reconcile() {
198 debug(`Persisting cached results: ${this.cacheFileLocation}`);
199 this.fileEntryCache.reconcile();
200 }
201}
202
203module.exports = LintResultCache;
Note: See TracBrowser for help on using the repository browser.